ordercloud-python 2026.6.1__tar.gz → 2026.10.2__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 (165) hide show
  1. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/dependabot.yml +6 -0
  2. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/ci.yml +7 -7
  3. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/codeql.yml +4 -4
  4. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/dependency-review.yml +1 -1
  5. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/release.yml +35 -7
  6. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/sbom.yml +2 -2
  7. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/scorecard.yml +3 -3
  8. ordercloud_python-2026.10.2/CHANGELOG.md +106 -0
  9. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/CONTRIBUTING.md +24 -0
  10. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/PKG-INFO +20 -15
  11. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/README.md +18 -13
  12. ordercloud_python-2026.10.2/SECURITY.md +70 -0
  13. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/pyproject.toml +6 -1
  14. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/http.py +40 -14
  15. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/middleware.py +7 -0
  16. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/api_client.py +0 -2
  17. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/discount.py +2 -0
  18. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/misc.py +1 -0
  19. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/forgotten_credentials.py +4 -1
  20. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/group_orders.py +6 -1
  21. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/me.py +37 -8
  22. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/sync_client.py +1 -3
  23. ordercloud_python-2026.10.2/tests/test_codegen_sensitivity.py +250 -0
  24. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_http.py +88 -1
  25. ordercloud_python-2026.10.2/tests/test_log_redaction.py +287 -0
  26. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_models.py +51 -0
  27. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_resources.py +42 -0
  28. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/cli.py +9 -0
  29. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/ir.py +7 -0
  30. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/renderer.py +26 -1
  31. ordercloud_python-2026.10.2/tools/codegen/sensitivity.py +172 -0
  32. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/resource_module.py.j2 +14 -14
  33. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/transformer.py +21 -1
  34. ordercloud_python-2026.6.1/CHANGELOG.md +0 -50
  35. ordercloud_python-2026.6.1/SECURITY.md +0 -41
  36. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.gitignore +0 -0
  37. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/CODE_REVIEW.md +0 -0
  38. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/LICENSE +0 -0
  39. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/SECURITY_AUDIT.md +0 -0
  40. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/examples/basic_workflow.py +0 -0
  41. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/__init__.py +0 -0
  42. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/auth.py +0 -0
  43. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/client.py +0 -0
  44. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/config.py +0 -0
  45. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/errors.py +0 -0
  46. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/__init__.py +0 -0
  47. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/address.py +0 -0
  48. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/approval.py +0 -0
  49. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/assignments.py +0 -0
  50. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/auth_models.py +0 -0
  51. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/bundle.py +0 -0
  52. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/buyer.py +0 -0
  53. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/catalog.py +0 -0
  54. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/category.py +0 -0
  55. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/cost_center.py +0 -0
  56. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/credit_card.py +0 -0
  57. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/delivery.py +0 -0
  58. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/integration.py +0 -0
  59. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/inventory_record.py +0 -0
  60. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/line_item.py +0 -0
  61. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/line_item_types.py +0 -0
  62. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/message_sender.py +0 -0
  63. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/open_id_connect.py +0 -0
  64. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/order.py +0 -0
  65. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/order_return.py +0 -0
  66. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/payment.py +0 -0
  67. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/price_schedule.py +0 -0
  68. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/product.py +0 -0
  69. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/product_collection.py +0 -0
  70. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/promotion.py +0 -0
  71. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/security.py +0 -0
  72. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/shared.py +0 -0
  73. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/shipment.py +0 -0
  74. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/spec.py +0 -0
  75. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/spending_account.py +0 -0
  76. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/subscription.py +0 -0
  77. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/supplier.py +0 -0
  78. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/sync.py +0 -0
  79. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/user.py +0 -0
  80. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/user_group.py +0 -0
  81. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/webhook.py +0 -0
  82. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/py.typed +0 -0
  83. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/__init__.py +0 -0
  84. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/addresses.py +0 -0
  85. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/admin_addresses.py +0 -0
  86. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/admin_user_groups.py +0 -0
  87. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/admin_users.py +0 -0
  88. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/api_clients.py +0 -0
  89. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/approval_rules.py +0 -0
  90. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/base.py +0 -0
  91. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/bundle_line_items.py +0 -0
  92. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/bundle_subscription_items.py +0 -0
  93. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/bundles.py +0 -0
  94. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/buyer_groups.py +0 -0
  95. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/buyers.py +0 -0
  96. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/cart.py +0 -0
  97. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/catalogs.py +0 -0
  98. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/categories.py +0 -0
  99. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/cost_centers.py +0 -0
  100. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/credit_cards.py +0 -0
  101. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/delivery_configurations.py +0 -0
  102. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/discounts.py +0 -0
  103. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/entity_syncs.py +0 -0
  104. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/error_configs.py +0 -0
  105. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/impersonation_configs.py +0 -0
  106. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/incrementors.py +0 -0
  107. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/integration_events.py +0 -0
  108. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/inventory_integrations.py +0 -0
  109. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/inventory_records.py +0 -0
  110. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/line_items.py +0 -0
  111. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/locales.py +0 -0
  112. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/message_senders.py +0 -0
  113. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/open_id_connects.py +0 -0
  114. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/order_returns.py +0 -0
  115. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/order_syncs.py +0 -0
  116. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/orders.py +0 -0
  117. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/payments.py +0 -0
  118. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/price_schedules.py +0 -0
  119. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/product_collections.py +0 -0
  120. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/product_facets.py +0 -0
  121. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/product_syncs.py +0 -0
  122. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/products.py +0 -0
  123. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/promotion_integrations.py +0 -0
  124. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/promotions.py +0 -0
  125. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/security_profiles.py +0 -0
  126. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/seller_approval_rules.py +0 -0
  127. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/shipments.py +0 -0
  128. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/specs.py +0 -0
  129. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/spending_accounts.py +0 -0
  130. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/subscription_integrations.py +0 -0
  131. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/subscription_items.py +0 -0
  132. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/subscriptions.py +0 -0
  133. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/supplier_addresses.py +0 -0
  134. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/supplier_user_groups.py +0 -0
  135. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/supplier_users.py +0 -0
  136. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/suppliers.py +0 -0
  137. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/tracking_events.py +0 -0
  138. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/user_groups.py +0 -0
  139. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/users.py +0 -0
  140. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/webhooks.py +0 -0
  141. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/xp_indices.py +0 -0
  142. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/__init__.py +0 -0
  143. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/conftest.py +0 -0
  144. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/__init__.py +0 -0
  145. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/conftest.py +0 -0
  146. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_auth.py +0 -0
  147. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_crud.py +0 -0
  148. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_errors.py +0 -0
  149. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_pagination.py +0 -0
  150. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_query_params.py +0 -0
  151. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_sync_client.py +0 -0
  152. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_auth.py +0 -0
  153. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_resource_coverage.py +0 -0
  154. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_sync_client.py +0 -0
  155. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/__init__.py +0 -0
  156. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/__init__.py +0 -0
  157. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/__main__.py +0 -0
  158. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/grouping.py +0 -0
  159. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/naming.py +0 -0
  160. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/parser.py +0 -0
  161. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/client.py.j2 +0 -0
  162. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/model_module.py.j2 +0 -0
  163. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/models_init.py.j2 +0 -0
  164. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/resources_init.py.j2 +0 -0
  165. {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/type_mapping.py +0 -0
@@ -24,3 +24,9 @@ updates:
24
24
  labels:
25
25
  - "ci"
26
26
  open-pull-requests-limit: 5
27
+ groups:
28
+ # The init / autobuild / analyze / upload-sarif steps must share one
29
+ # version, so they are bumped together in a single PR.
30
+ codeql-action:
31
+ patterns:
32
+ - "github/codeql-action*"
@@ -14,8 +14,8 @@ jobs:
14
14
  name: Lint
15
15
  runs-on: ubuntu-latest
16
16
  steps:
17
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
18
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
17
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
18
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
19
19
  with:
20
20
  python-version: "3.13"
21
21
  - name: Install ruff
@@ -29,8 +29,8 @@ jobs:
29
29
  name: Type check
30
30
  runs-on: ubuntu-latest
31
31
  steps:
32
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
33
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
32
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
34
34
  with:
35
35
  python-version: "3.13"
36
36
  - name: Install dependencies
@@ -46,8 +46,8 @@ jobs:
46
46
  matrix:
47
47
  python-version: ["3.10", "3.11", "3.12", "3.13"]
48
48
  steps:
49
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
50
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
49
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
50
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
51
51
  with:
52
52
  python-version: ${{ matrix.python-version }}
53
53
  - name: Install dependencies
@@ -56,7 +56,7 @@ jobs:
56
56
  run: pytest --cov=ordercloud --cov-report=xml --cov-report=term-missing --cov-fail-under=90
57
57
  - name: Upload coverage to Codecov
58
58
  if: matrix.python-version == '3.13'
59
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
59
+ uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
60
60
  with:
61
61
  files: ./coverage.xml
62
62
  fail_ci_if_error: false
@@ -18,18 +18,18 @@ jobs:
18
18
  name: Analyze (Python)
19
19
  runs-on: ubuntu-latest
20
20
  steps:
21
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
22
 
23
23
  - name: Initialize CodeQL
24
- uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
24
+ uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
25
25
  with:
26
26
  languages: python
27
27
  queries: security-and-quality
28
28
 
29
29
  - name: Autobuild
30
- uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
30
+ uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
31
31
 
32
32
  - name: Perform CodeQL Analysis
33
- uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
33
+ uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
34
34
  with:
35
35
  category: "/language:python"
@@ -12,7 +12,7 @@ jobs:
12
12
  name: Review dependencies
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
16
16
  - name: Dependency Review
17
17
  uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
18
18
  with:
@@ -14,8 +14,8 @@ jobs:
14
14
  permissions:
15
15
  contents: read
16
16
  steps:
17
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
18
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
17
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
18
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
19
19
  with:
20
20
  python-version: "3.13"
21
21
  - name: Install build
@@ -38,7 +38,8 @@ jobs:
38
38
 
39
39
  publish:
40
40
  name: Publish to PyPI
41
- needs: build
41
+ # The PyPI upload cannot be undone, so it runs only after attestation.
42
+ needs: attestation
42
43
  runs-on: ubuntu-latest
43
44
  permissions:
44
45
  id-token: write
@@ -52,7 +53,7 @@ jobs:
52
53
  name: dist
53
54
  path: dist/
54
55
  - name: Publish to PyPI
55
- uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
56
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
56
57
 
57
58
  attestation:
58
59
  name: Attest build provenance
@@ -69,9 +70,26 @@ jobs:
69
70
  name: dist
70
71
  path: dist/
71
72
  - name: Attest build provenance
72
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
73
+ id: attest
74
+ uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
73
75
  with:
74
76
  subject-path: dist/*
77
+ - name: Name provenance file
78
+ env:
79
+ BUNDLE_PATH: ${{ steps.attest.outputs.bundle-path }}
80
+ run: |
81
+ if [ ! -s "$BUNDLE_PATH" ]; then
82
+ echo "::error::Attestation bundle is missing or empty: $BUNDLE_PATH"
83
+ exit 1
84
+ fi
85
+ mkdir provenance
86
+ cp "$BUNDLE_PATH" "provenance/ordercloud_python-${GITHUB_REF_NAME#v}.intoto.jsonl"
87
+ - name: Upload provenance
88
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
89
+ with:
90
+ name: provenance
91
+ path: provenance/
92
+ if-no-files-found: error
75
93
 
76
94
  github-release:
77
95
  name: Create GitHub Release
@@ -80,16 +98,26 @@ jobs:
80
98
  permissions:
81
99
  contents: write
82
100
  steps:
83
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
101
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
84
102
  - name: Download distributions
85
103
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
86
104
  with:
87
105
  name: dist
88
106
  path: dist/
107
+ - name: Download provenance
108
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
109
+ with:
110
+ name: provenance
111
+ path: provenance/
89
112
  - name: Create GitHub Release
90
113
  env:
91
114
  GH_TOKEN: ${{ github.token }}
92
115
  run: |
93
- gh release create "$GITHUB_REF_NAME" dist/* \
116
+ PROVENANCE="provenance/ordercloud_python-${GITHUB_REF_NAME#v}.intoto.jsonl"
117
+ if [ ! -s "$PROVENANCE" ]; then
118
+ echo "::error::Provenance file is missing or empty: $PROVENANCE"
119
+ exit 1
120
+ fi
121
+ gh release create "$GITHUB_REF_NAME" dist/* "$PROVENANCE" \
94
122
  --title "$GITHUB_REF_NAME" \
95
123
  --generate-notes
@@ -16,10 +16,10 @@ jobs:
16
16
  permissions:
17
17
  contents: read
18
18
  steps:
19
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20
20
 
21
21
  - name: Generate SBOM
22
- uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0
22
+ uses: anchore/sbom-action@66cbf4bc1f1c0d2edc94016e65bc221b6bb0ad6c # v0.24.3
23
23
  with:
24
24
  format: spdx-json
25
25
  output-file: sbom.spdx.json
@@ -19,18 +19,18 @@ jobs:
19
19
  contents: read
20
20
  actions: read
21
21
  steps:
22
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
23
  with:
24
24
  persist-credentials: false
25
25
 
26
26
  - name: Run Scorecard
27
- uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
27
+ uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
28
28
  with:
29
29
  results_file: results.sarif
30
30
  results_format: sarif
31
31
  publish_results: true
32
32
 
33
33
  - name: Upload SARIF results
34
- uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
34
+ uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
35
35
  with:
36
36
  sarif_file: results.sarif
@@ -0,0 +1,106 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ This project uses [Calendar Versioning](https://calver.org/) — `YYYY.MM.N` where `N` is the release number within that month.
6
+
7
+ ## 2026.10.2 — 2026-10-05
8
+
9
+ ### Security
10
+
11
+ - **Credential-bearing path values are no longer written to the SDK's log lines.** The SDK logs requests on the `ordercloud` logger: a `Request:` and a `Response:` line at `DEBUG` for every request, and a `Retry` line at `WARNING` before each retry (retries are off unless `max_retries` is set). In 2026.4.1, 2026.6.1 and 2026.10.1 each of these lines contained the full request path. Two path parameters in the OrderCloud spec carry values that work as credentials, so those values reached the log:
12
+ - `verificationCode`, in `forgotten_credentials.reset_password_by_verification_code` (`PUT /password/reset/{verificationCode}`).
13
+ - `invitationID`, in `group_orders.get_token` (`POST /grouporders/{invitationID}/token`, which returns an `AccessToken`). The spec says of group-order invitations: "Contributors may request an access token with the invitation ID".
14
+
15
+ The SDK classifies path parameters by name, so every operation that takes an `invitationID` is covered: `group_orders.get_token`, and on `me` the three group-order invitation operations (`get_` / `delete_` / `patch_group_order_invitation`) and the five product-collection invitation operations (`get_` / `delete_` / `patch_` / `accept_` / `decline_product_collection_invitation`). On these ten operations the SDK's log lines now show `***` in place of the value, for example `Request: PUT /password/reset/***` and `Request: POST /me/productcollections/col-1/invitations/accept/***`. Other path values, and the log lines of every other operation, are unchanged.
16
+ - **What this release does not change:**
17
+ - `httpx` writes its own `HTTP Request: <METHOD> <URL> ...` line at `INFO` on the `httpx` logger, with the full URL including the query string. The SDK does not control that logger. If your application logs at `INFO` or below, set `logging.getLogger("httpx").setLevel(logging.WARNING)`. See [SECURITY.md](SECURITY.md#logging).
18
+ - Middleware hooks receive the concrete values: `RequestContext.path`, `url` and `params` are what is sent to the API.
19
+ - Exceptions that `httpx` raises for transport failures (timeouts, connection errors) carry the request, and with it the full URL, as their `request` attribute.
20
+ - The code generator now refuses to generate while any path-parameter name in the spec is unclassified. Every name is listed in `tools/codegen/sensitivity.py` as sensitive or not sensitive, and a name missing from the not-sensitive list is redacted. See [CONTRIBUTING.md](CONTRIBUTING.md#path-parameter-classification).
21
+
22
+ ### Changed
23
+
24
+ - Bumped package version to `2026.10.2` (CalVer).
25
+ - `HttpClient.request()` and its `get` / `post` / `put` / `patch` / `delete` helpers accept a `SensitivePath` (new, in `ordercloud.http`) as well as a plain string path. Generated resource method signatures are unchanged.
26
+ - Removed an unused module-level `TypeVar` from `ordercloud.sync_client`.
27
+
28
+ ## 2026.10.1 — 2026-10-05
29
+
30
+ Regenerated from the OrderCloud OpenAPI v3 spec, **version 1.0.454 → 1.0.470**. This release contains **one breaking change** — `ApiClient.client_secret` is removed — which the CalVer version number does not signal. Coverage is unchanged: **639 operations** across 60 resources, with 173 models and 17 enums.
31
+
32
+ ### Breaking
33
+
34
+ - **`ApiClient.client_secret` (`ClientSecret`) removed**, following its removal from the `ApiClient` schema in the spec. `ApiClient` keeps the models' `extra="allow"` configuration, so code that still uses the field now behaves as follows:
35
+ - Reading `.client_secret` on an `ApiClient` that was not given one raises `AttributeError` (it previously returned `None`).
36
+ - mypy reports any `.client_secret` access as an `attr-defined` error.
37
+ - A `ClientSecret` value in an API response is no longer available as `.client_secret`; it is kept as an undeclared extra under its API name, in `model_extra["ClientSecret"]`.
38
+ - `ApiClient(ClientSecret="...")` is accepted, and the value is still sent to the API under the key `ClientSecret`.
39
+ - `ApiClient(client_secret="...")` is accepted, but the value is now sent to the API under the snake_case key `client_secret` instead of `ClientSecret`.
40
+ - Request bodies passed as plain dicts are sent unchanged.
41
+
42
+ The five API-client secret operations (`ApiClients.ListSecrets` / `CreateSecret` / `GetSecret` / `PatchSecret` / `DeleteSecret`) and the `ApiClientSecret` / `ApiClientSecretCreateResponse` models are unchanged in this release.
43
+
44
+ ### Added
45
+
46
+ - **`Discount.priority`** (`Priority`, integer). The spec describes it as: "Controls precedence when multiple discounts apply to the same user and product. Lower number = higher precedence (1 beats 2). Null is applied last."
47
+ - **`OrderEditAfterSubmit`** added to the `ApiRole` enum. Role lists that contain it (for example `SecurityProfile.roles` or `ApiClient.maximum_granted_roles`) now validate; on 2026.6.1 they raise a pydantic `ValidationError`.
48
+
49
+ ### Spec changes with no SDK code change
50
+
51
+ - The `x-lifecycle: Beta` marker is removed from the Discounts tag and its nine operations. The code generator does not read this marker.
52
+ - `GET /discounts` now lists `Priority` and `!Priority` as `sortBy` values. `Discounts.list` takes `sort_by` as a plain string and passes it through unvalidated, so no SDK change was needed.
53
+ - `OrderEditAfterSubmit` is also added to the spec's OAuth2 scopes. The SDK's `scopes` setting takes plain strings.
54
+
55
+ ### Release artefacts
56
+
57
+ - GitHub releases now also attach the build provenance attestation for the sdist and wheel, as `ordercloud_python-<version>.intoto.jsonl`, alongside the distributions themselves.
58
+
59
+ ### Changed
60
+
61
+ - Bumped package version to `2026.10.1` (CalVer).
62
+
63
+ ## 2026.6.1 — 2026-06-14
64
+
65
+ Regenerated from the OrderCloud OpenAPI v3 spec, **version 1.0.445 → 1.0.454**. All changes are additive — no breaking changes to existing models or operations. Coverage now spans **639 operations** (was 632) across the same 60 resources, with **173 models** and 17 enums.
66
+
67
+ ### Added
68
+
69
+ - **Generated promotion codes** — `Promotions.ListCodes` (`GET /promotions/{promotionID}/codes`), the `PromotionCode` model, and `GeneratedCodeCount` / `GeneratedCodeLength` / `GeneratedCodePrefix` fields on the `Promotion` model family (`Promotion`, `OrderPromotion`, `AddedPromo`, `RemovedPromo`, `EligiblePromotion`).
70
+ - **Repeat order** — `Orders.Repeat` (`POST /orders/{direction}/{orderID}/repeat`) with the `OrderRepeatResponse` and `UnavailableLineItem` models.
71
+ - **Catalog entity sync** — five `EntitySyncs` catalog operations (get / save / patch / delete on `/integrations/entitysync/catalogs`, plus `/catalogs/sync`) and the `SyncCatalog` model.
72
+ - **New models** — `BuyerDiscount` (on `BuyerPriceSchedule`) and `ApiError` (the typed error returned within `UnavailableLineItem`).
73
+ - **New fields / values** — `Percent` on `DiscountedPrices`; `BulkReader` added to the `ApiRole` enum.
74
+
75
+ ### Changed
76
+
77
+ - Bumped package version to `2026.6.1` (CalVer).
78
+
79
+ ## 2026.4.1 — 2026-04-13
80
+
81
+ Initial release. Full SDK for the Sitecore OrderCloud API, generated from the OpenAPI v3 spec (version 1.0.445).
82
+
83
+ ### Features
84
+
85
+ - **Full API coverage** — 632 operations across 60 resources, generated from the official OpenAPI spec
86
+ - **Async and sync clients** — `OrderCloudClient` (async, default) and `SyncOrderCloudClient` with identical API shapes
87
+ - **Pydantic v2 typed models** — 167 models and 17 enums with full type annotations
88
+ - **Typed extended properties (xp)** — `Product[MyXp]` pattern for type-safe custom fields, backward compatible with untyped `dict[str, Any]`
89
+ - **Auto-pagination** — `paginate()` and `paginate_sync()` async/sync generators for any list method
90
+ - **Retry with exponential backoff** — configurable `max_retries` and `retry_backoff`; retries 429/5xx, respects `Retry-After` headers
91
+ - **Structured logging** — `logging.getLogger("ordercloud")` with DEBUG request/response and WARNING retry logging
92
+ - **Middleware hooks** — `add_before_request()` / `add_after_response()` for request/response interception
93
+ - **OAuth2 client credentials** — automatic token acquisition, caching, and refresh
94
+ - **PEP 561 typed** — `py.typed` marker for downstream type checking
95
+
96
+ ### Code Generation
97
+
98
+ Three-stage pipeline in `tools/codegen/`: OpenAPI JSON -> parser -> IR dataclasses -> transformer -> Jinja2 templates -> Python source -> ruff format. 10 source files, 5 templates. Generates 100 files (37 model modules, 60 resource modules, 2 init barrels, 1 client).
99
+
100
+ ### Quality
101
+
102
+ - 759 unit tests, 97% overall coverage (100% on all hand-written infrastructure and all 37 model modules)
103
+ - CI: lint, format, type check (mypy strict), test matrix (Python 3.10-3.13), coverage upload
104
+ - CodeQL security scanning, OpenSSF Scorecard, SBOM generation, dependency review
105
+ - Dependabot for pip and GitHub Actions version management
106
+ - Branch protection with required status checks
@@ -99,8 +99,32 @@ If you need to change how models or resources are structured, the relevant files
99
99
  - `tools/codegen/ir.py` — intermediate representation dataclasses
100
100
  - `tools/codegen/parser.py` — OpenAPI spec to IR
101
101
  - `tools/codegen/transformer.py` — IR enrichment (imports, grouping)
102
+ - `tools/codegen/sensitivity.py` — path-parameter sensitivity registry (see below)
102
103
  - `tools/codegen/templates/*.j2` — Jinja2 templates for output files
103
104
 
105
+ ### Path-parameter classification
106
+
107
+ The SDK logs the path of every request, and some path parameters carry values that work as credentials. Every path-parameter name in the spec is therefore classified in `tools/codegen/sensitivity.py`, in exactly one of two sets:
108
+
109
+ - `SENSITIVE_PATH_PARAMS` — anyone who reads the value from a log could use it to authenticate, obtain a token, or perform an account action without the account owner's own credentials.
110
+ - `NOT_SENSITIVE_PATH_PARAMS` — record identifiers that grant nothing without the caller's own authorisation.
111
+
112
+ When uncertain, choose sensitive. `NOT_SENSITIVE_PATH_PARAMS` is an allowlist: a parameter whose name is not on it is generated as a `SensitivePath`, and the SDK logs `***` in its place.
113
+
114
+ Generation stops with exit code 1, before any file is written, if a path-parameter name in the spec is unclassified, is in both sets, or is classified but no longer in the spec. A new, unclassified name fails like this (`shareToken` is an example, not a real parameter):
115
+
116
+ ```
117
+ Error: Path parameter 'shareToken' is not classified (used by Products.GetShareLink); add it to SENSITIVE_PATH_PARAMS or NOT_SENSITIVE_PATH_PARAMS in tools/codegen/sensitivity.py
118
+ ```
119
+
120
+ To resolve it:
121
+
122
+ 1. Read what the value is in the spec: the operations named in the error, their descriptions, and what they return.
123
+ 2. Apply the rule above and add the name to one of the two sets, with a comment giving the reason.
124
+ 3. Regenerate and run the tests. `tests/test_log_redaction.py` scans every generated request path and fails if one could log an unclassified or sensitive value.
125
+
126
+ The classification is by name, so the gate cannot tell when a new spec reuses an already-cleared name for a credential-bearing value. Review the spec diff at each spec bump for that.
127
+
104
128
  ## Conventions
105
129
 
106
130
  - **snake_case** for all Python identifiers. Model fields use snake_case with PascalCase aliases matching the API.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: ordercloud-python
3
- Version: 2026.6.1
3
+ Version: 2026.10.2
4
4
  Summary: Idiomatic Python SDK for Sitecore OrderCloud
5
5
  Project-URL: Homepage, https://github.com/markcassidyconsulting/ordercloud-python
6
6
  Project-URL: Repository, https://github.com/markcassidyconsulting/ordercloud-python
@@ -60,7 +60,7 @@ A fully typed, async-first Python SDK for [Sitecore OrderCloud](https://orderclo
60
60
  - **Middleware hooks** — intercept requests and responses for logging, metrics, or header injection.
61
61
  - **Structured logging** — standard Python `logging` module, DEBUG/WARNING levels.
62
62
  - **Full type annotations** — `py.typed` marker for downstream type checking with mypy, pyright, etc.
63
- - **791 tests, 97% coverage** — 766 unit tests (mocked HTTP) + 25 integration tests (live sandbox).
63
+ - **803 tests, 97% coverage** — 778 unit tests (mocked HTTP) + 25 integration tests (live sandbox).
64
64
 
65
65
  ## Installation
66
66
 
@@ -212,9 +212,8 @@ The SDK logs via Python's standard `logging` module under the `ordercloud` logge
212
212
 
213
213
  ```python
214
214
  import logging
215
- logging.basicConfig(level=logging.DEBUG)
216
215
 
217
- # Or configure just the SDK logger
216
+ logging.basicConfig() # adds a handler; the root logger stays at WARNING
218
217
  logging.getLogger("ordercloud").setLevel(logging.DEBUG)
219
218
  ```
220
219
 
@@ -223,6 +222,10 @@ logging.getLogger("ordercloud").setLevel(logging.DEBUG)
223
222
  | `DEBUG` | Every request (`Request: GET /products`) and response (`Response: GET /products 200`) |
224
223
  | `WARNING` | Retry attempts with status code and backoff delay |
225
224
 
225
+ Path values that work as credentials, a password-reset verification code and an invitation ID, are logged as `***`, for example `Request: PUT /password/reset/***`. Query parameters and request bodies are not logged.
226
+
227
+ Setting the root logger to `INFO` or `DEBUG` (for example `logging.basicConfig(level=logging.DEBUG)`) also turns on `httpx`'s own `HTTP Request:` line, which contains the full URL, unredacted, including the query string. The SDK does not control that logger. To keep it quiet, add `logging.getLogger("httpx").setLevel(logging.WARNING)`. See [SECURITY.md](SECURITY.md#logging).
228
+
226
229
  ## Middleware Hooks
227
230
 
228
231
  Register hooks to intercept requests and responses:
@@ -242,9 +245,11 @@ client.add_after_response(log_timing)
242
245
 
243
246
  Before-request hooks receive a mutable `RequestContext` — modify `headers`, `params`, or `json` before the request is sent. After-response hooks receive a `ResponseContext` with the request details and response. Hooks are called on every attempt, including retries.
244
247
 
248
+ Hooks see the concrete values sent to the API, including credential-bearing path values and the `Authorization` header; the redaction above applies only to the SDK's own log lines.
249
+
245
250
  ## API Coverage
246
251
 
247
- The SDK covers **all 60 resources** and **639 operations** in the OrderCloud API. Models and resource clients are generated from the official OpenAPI v3 spec (version 1.0.454).
252
+ The SDK covers **all 60 resources** and **639 operations** in the OrderCloud API. Models and resource clients are generated from the official OpenAPI v3 spec (version 1.0.470).
248
253
 
249
254
  ### Core Commerce
250
255
 
@@ -504,18 +509,18 @@ The test suite is self-bootstrapping — it uses the SDK itself to create all te
504
509
 
505
510
  ### Test Suite
506
511
 
507
- 791 tests across 12 modules.
512
+ 803 tests across 12 modules.
508
513
 
509
- **Unit tests (766)** — mocked HTTP via [respx](https://lundberg.github.io/respx/), no network calls:
514
+ **Unit tests (778)** — mocked HTTP via [respx](https://lundberg.github.io/respx/), no network calls:
510
515
 
511
516
  | Module | Tests | Purpose |
512
517
  |--------|-------|---------|
513
518
  | `test_auth.py` | 13 | OAuth2 token management |
514
- | `test_http.py` | 16 | HTTP client, error parsing, retries |
515
- | `test_models.py` | 28 | Model round-trips, enums, xp, ListPage |
516
- | `test_resources.py` | 22 | Representative resource operations |
519
+ | `test_http.py` | 37 | HTTP client, error parsing, retries |
520
+ | `test_models.py` | 44 | Model round-trips, enums, xp, ListPage |
521
+ | `test_resources.py` | 33 | Representative resource operations |
517
522
  | `test_resource_coverage.py` | 639 | All 60 resources, all 639 operations |
518
- | `test_sync_client.py` | 48 | Sync wrapper, pagination |
523
+ | `test_sync_client.py` | 12 | Sync wrapper, pagination |
519
524
 
520
525
  **Integration tests (25)** — live sandbox, skipped when credentials are absent:
521
526
 
@@ -532,11 +537,11 @@ The test suite is self-bootstrapping — it uses the SDK itself to create all te
532
537
 
533
538
  | Module | Coverage |
534
539
  |--------|----------|
535
- | `auth.py` | 100% |
540
+ | `auth.py` | 93% |
536
541
  | `client.py` | 100% |
537
- | `config.py` | 100% |
542
+ | `config.py` | 94% |
538
543
  | `errors.py` | 100% |
539
- | `http.py` | 97% |
544
+ | `http.py` | 98% |
540
545
  | `middleware.py` | 100% |
541
546
  | `sync_client.py` | 100% |
542
547
  | `resources/base.py` | 100% |
@@ -20,7 +20,7 @@ A fully typed, async-first Python SDK for [Sitecore OrderCloud](https://orderclo
20
20
  - **Middleware hooks** — intercept requests and responses for logging, metrics, or header injection.
21
21
  - **Structured logging** — standard Python `logging` module, DEBUG/WARNING levels.
22
22
  - **Full type annotations** — `py.typed` marker for downstream type checking with mypy, pyright, etc.
23
- - **791 tests, 97% coverage** — 766 unit tests (mocked HTTP) + 25 integration tests (live sandbox).
23
+ - **803 tests, 97% coverage** — 778 unit tests (mocked HTTP) + 25 integration tests (live sandbox).
24
24
 
25
25
  ## Installation
26
26
 
@@ -172,9 +172,8 @@ The SDK logs via Python's standard `logging` module under the `ordercloud` logge
172
172
 
173
173
  ```python
174
174
  import logging
175
- logging.basicConfig(level=logging.DEBUG)
176
175
 
177
- # Or configure just the SDK logger
176
+ logging.basicConfig() # adds a handler; the root logger stays at WARNING
178
177
  logging.getLogger("ordercloud").setLevel(logging.DEBUG)
179
178
  ```
180
179
 
@@ -183,6 +182,10 @@ logging.getLogger("ordercloud").setLevel(logging.DEBUG)
183
182
  | `DEBUG` | Every request (`Request: GET /products`) and response (`Response: GET /products 200`) |
184
183
  | `WARNING` | Retry attempts with status code and backoff delay |
185
184
 
185
+ Path values that work as credentials, a password-reset verification code and an invitation ID, are logged as `***`, for example `Request: PUT /password/reset/***`. Query parameters and request bodies are not logged.
186
+
187
+ Setting the root logger to `INFO` or `DEBUG` (for example `logging.basicConfig(level=logging.DEBUG)`) also turns on `httpx`'s own `HTTP Request:` line, which contains the full URL, unredacted, including the query string. The SDK does not control that logger. To keep it quiet, add `logging.getLogger("httpx").setLevel(logging.WARNING)`. See [SECURITY.md](SECURITY.md#logging).
188
+
186
189
  ## Middleware Hooks
187
190
 
188
191
  Register hooks to intercept requests and responses:
@@ -202,9 +205,11 @@ client.add_after_response(log_timing)
202
205
 
203
206
  Before-request hooks receive a mutable `RequestContext` — modify `headers`, `params`, or `json` before the request is sent. After-response hooks receive a `ResponseContext` with the request details and response. Hooks are called on every attempt, including retries.
204
207
 
208
+ Hooks see the concrete values sent to the API, including credential-bearing path values and the `Authorization` header; the redaction above applies only to the SDK's own log lines.
209
+
205
210
  ## API Coverage
206
211
 
207
- The SDK covers **all 60 resources** and **639 operations** in the OrderCloud API. Models and resource clients are generated from the official OpenAPI v3 spec (version 1.0.454).
212
+ The SDK covers **all 60 resources** and **639 operations** in the OrderCloud API. Models and resource clients are generated from the official OpenAPI v3 spec (version 1.0.470).
208
213
 
209
214
  ### Core Commerce
210
215
 
@@ -464,18 +469,18 @@ The test suite is self-bootstrapping — it uses the SDK itself to create all te
464
469
 
465
470
  ### Test Suite
466
471
 
467
- 791 tests across 12 modules.
472
+ 803 tests across 12 modules.
468
473
 
469
- **Unit tests (766)** — mocked HTTP via [respx](https://lundberg.github.io/respx/), no network calls:
474
+ **Unit tests (778)** — mocked HTTP via [respx](https://lundberg.github.io/respx/), no network calls:
470
475
 
471
476
  | Module | Tests | Purpose |
472
477
  |--------|-------|---------|
473
478
  | `test_auth.py` | 13 | OAuth2 token management |
474
- | `test_http.py` | 16 | HTTP client, error parsing, retries |
475
- | `test_models.py` | 28 | Model round-trips, enums, xp, ListPage |
476
- | `test_resources.py` | 22 | Representative resource operations |
479
+ | `test_http.py` | 37 | HTTP client, error parsing, retries |
480
+ | `test_models.py` | 44 | Model round-trips, enums, xp, ListPage |
481
+ | `test_resources.py` | 33 | Representative resource operations |
477
482
  | `test_resource_coverage.py` | 639 | All 60 resources, all 639 operations |
478
- | `test_sync_client.py` | 48 | Sync wrapper, pagination |
483
+ | `test_sync_client.py` | 12 | Sync wrapper, pagination |
479
484
 
480
485
  **Integration tests (25)** — live sandbox, skipped when credentials are absent:
481
486
 
@@ -492,11 +497,11 @@ The test suite is self-bootstrapping — it uses the SDK itself to create all te
492
497
 
493
498
  | Module | Coverage |
494
499
  |--------|----------|
495
- | `auth.py` | 100% |
500
+ | `auth.py` | 93% |
496
501
  | `client.py` | 100% |
497
- | `config.py` | 100% |
502
+ | `config.py` | 94% |
498
503
  | `errors.py` | 100% |
499
- | `http.py` | 97% |
504
+ | `http.py` | 98% |
500
505
  | `middleware.py` | 100% |
501
506
  | `sync_client.py` | 100% |
502
507
  | `resources/base.py` | 100% |
@@ -0,0 +1,70 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ |---------|--------------------|
7
+ | Latest | :white_check_mark: |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ If you discover a security vulnerability in this project, please report it responsibly.
12
+
13
+ **Do not open a public GitHub issue for security vulnerabilities.**
14
+
15
+ Instead, email **mark.cassidy@markcassidyconsulting.com** with:
16
+
17
+ - A description of the vulnerability
18
+ - Steps to reproduce or a proof of concept
19
+ - The potential impact
20
+
21
+ You will receive an acknowledgement within 48 hours and a detailed response within 5 business days, including next steps and any planned fixes.
22
+
23
+ If the vulnerability is confirmed, a fix will be developed and released as a patch version. A security advisory will be published via [GitHub Security Advisories](https://github.com/markcassidyconsulting/ordercloud-python/security/advisories) once a fix is available.
24
+
25
+ ## Scope
26
+
27
+ This SDK is an HTTP client library. It does not run a server, store credentials persistently, or process untrusted input beyond what the OrderCloud API returns. Security concerns most likely relate to:
28
+
29
+ - Credential handling (OAuth tokens in memory)
30
+ - Dependency vulnerabilities (tracked via Dependabot and `dependency-review`)
31
+ - Injection via API response data (mitigated by Pydantic model validation)
32
+
33
+ ## Logging
34
+
35
+ The SDK writes request log lines to the `ordercloud` logger (see [Structured Logging](README.md#structured-logging)). Path values that work as credentials, a password-reset `verificationCode` and an `invitationID`, appear in those lines as `***`. Every path-parameter name in the OrderCloud spec is classified as sensitive or not sensitive when the SDK is generated, and an unclassified name stops generation. Query parameters and request bodies are not written to these lines.
36
+
37
+ The SDK does not control what other code logs:
38
+
39
+ - **`httpx` logs the full URL.** For every request, `httpx` writes `HTTP Request: <METHOD> <URL> "<HTTP version> <status> <reason>"` at `INFO` on the `httpx` logger, with the full URL including the path and the query string (checked against the httpx 0.28.1 source). The line appears whenever that logger is enabled for `INFO`, for example after `logging.basicConfig(level=logging.INFO)` or `level=logging.DEBUG`. To keep it out of your logs:
40
+
41
+ ```python
42
+ import logging
43
+
44
+ logging.getLogger("httpx").setLevel(logging.WARNING)
45
+ ```
46
+
47
+ - **`httpx` exceptions carry the request.** Exceptions that `httpx` raises for transport failures (timeouts, connection errors) carry the request as their `request` attribute, and `exc.request.url` is the full URL.
48
+ - **Middleware hooks receive the concrete values.** `RequestContext.path`, `url` and `params` are the values sent to the API, and `headers` holds the `Authorization` bearer token. A hook that logs them must redact them itself.
49
+
50
+ ## Security Measures
51
+
52
+ This project employs the following security practices:
53
+
54
+ - **Static analysis:** [CodeQL](https://github.com/markcassidyconsulting/ordercloud-python/actions/workflows/codeql.yml) runs on every push and weekly
55
+ - **Dependency scanning:** [Dependabot](https://github.com/markcassidyconsulting/ordercloud-python/security/dependabot) monitors for known vulnerabilities in dependencies
56
+ - **Dependency review:** Pull requests are checked for newly introduced vulnerable dependencies
57
+ - **Supply chain security:** All GitHub Actions are pinned to commit SHAs
58
+ - **Build provenance:** Every [GitHub release](https://github.com/markcassidyconsulting/ordercloud-python/releases) carries the build provenance attestation for its sdist and wheel as `ordercloud_python-<version>.intoto.jsonl`
59
+ - **Branch protection:** The `main` branch requires status checks to pass before merge
60
+
61
+ ### Verifying a release
62
+
63
+ With the [GitHub CLI](https://cli.github.com/), download a release's files and check a distribution against its provenance file:
64
+
65
+ ```bash
66
+ gh release download v<version> --repo markcassidyconsulting/ordercloud-python
67
+ gh attestation verify ordercloud_python-<version>-py3-none-any.whl --bundle ordercloud_python-<version>.intoto.jsonl --repo markcassidyconsulting/ordercloud-python
68
+ ```
69
+
70
+ The provenance file covers both the wheel and the sdist (`ordercloud_python-<version>.tar.gz`), and the same command checks a wheel fetched from PyPI with `pip download ordercloud-python==<version> --no-deps`. Exit code 0 means the file matches build provenance signed by a GitHub Actions workflow in this repository; a modified file fails verification.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ordercloud-python"
7
- version = "2026.6.1"
7
+ version = "2026.10.2"
8
8
  description = "Idiomatic Python SDK for Sitecore OrderCloud"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -70,6 +70,11 @@ packages = ["src/ordercloud"]
70
70
  target-version = "py310"
71
71
  line-length = 100
72
72
 
73
+ [tool.ruff.lint]
74
+ # Explicit rule selection: the set this codebase is linted against. Stated
75
+ # here so the gate does not change when Ruff changes its default rules.
76
+ select = ["E4", "E7", "E9", "F"]
77
+
73
78
  [tool.pytest.ini_options]
74
79
  testpaths = ["tests"]
75
80
  asyncio_mode = "auto"