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.
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/dependabot.yml +6 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/ci.yml +7 -7
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/codeql.yml +4 -4
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/dependency-review.yml +1 -1
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/release.yml +35 -7
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/sbom.yml +2 -2
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/scorecard.yml +3 -3
- ordercloud_python-2026.10.2/CHANGELOG.md +106 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/CONTRIBUTING.md +24 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/PKG-INFO +20 -15
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/README.md +18 -13
- ordercloud_python-2026.10.2/SECURITY.md +70 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/pyproject.toml +6 -1
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/http.py +40 -14
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/middleware.py +7 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/api_client.py +0 -2
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/discount.py +2 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/misc.py +1 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/forgotten_credentials.py +4 -1
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/group_orders.py +6 -1
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/me.py +37 -8
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/sync_client.py +1 -3
- ordercloud_python-2026.10.2/tests/test_codegen_sensitivity.py +250 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_http.py +88 -1
- ordercloud_python-2026.10.2/tests/test_log_redaction.py +287 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_models.py +51 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_resources.py +42 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/cli.py +9 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/ir.py +7 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/renderer.py +26 -1
- ordercloud_python-2026.10.2/tools/codegen/sensitivity.py +172 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/resource_module.py.j2 +14 -14
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/transformer.py +21 -1
- ordercloud_python-2026.6.1/CHANGELOG.md +0 -50
- ordercloud_python-2026.6.1/SECURITY.md +0 -41
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.gitignore +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/CODE_REVIEW.md +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/LICENSE +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/SECURITY_AUDIT.md +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/examples/basic_workflow.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/__init__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/auth.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/client.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/config.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/errors.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/__init__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/address.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/approval.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/assignments.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/auth_models.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/bundle.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/buyer.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/catalog.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/category.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/cost_center.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/credit_card.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/delivery.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/integration.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/inventory_record.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/line_item.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/line_item_types.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/message_sender.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/open_id_connect.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/order.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/order_return.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/payment.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/price_schedule.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/product.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/product_collection.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/promotion.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/security.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/shared.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/shipment.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/spec.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/spending_account.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/subscription.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/supplier.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/sync.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/user.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/user_group.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/models/webhook.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/py.typed +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/__init__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/addresses.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/admin_addresses.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/admin_user_groups.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/admin_users.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/api_clients.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/approval_rules.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/base.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/bundle_line_items.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/bundle_subscription_items.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/bundles.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/buyer_groups.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/buyers.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/cart.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/catalogs.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/categories.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/cost_centers.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/credit_cards.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/delivery_configurations.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/discounts.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/entity_syncs.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/error_configs.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/impersonation_configs.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/incrementors.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/integration_events.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/inventory_integrations.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/inventory_records.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/line_items.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/locales.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/message_senders.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/open_id_connects.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/order_returns.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/order_syncs.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/orders.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/payments.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/price_schedules.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/product_collections.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/product_facets.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/product_syncs.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/products.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/promotion_integrations.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/promotions.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/security_profiles.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/seller_approval_rules.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/shipments.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/specs.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/spending_accounts.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/subscription_integrations.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/subscription_items.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/subscriptions.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/supplier_addresses.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/supplier_user_groups.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/supplier_users.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/suppliers.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/tracking_events.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/user_groups.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/users.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/webhooks.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/src/ordercloud/resources/xp_indices.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/__init__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/conftest.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/__init__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/conftest.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_auth.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_crud.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_errors.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_pagination.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_query_params.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/integration/test_sync_client.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_auth.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_resource_coverage.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tests/test_sync_client.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/__init__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/__init__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/__main__.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/grouping.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/naming.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/parser.py +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/client.py.j2 +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/model_module.py.j2 +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/models_init.py.j2 +0 -0
- {ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/tools/codegen/templates/resources_init.py.j2 +0 -0
- {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@
|
|
18
|
-
- uses: actions/setup-python@
|
|
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@
|
|
33
|
-
- uses: actions/setup-python@
|
|
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@
|
|
50
|
-
- uses: actions/setup-python@
|
|
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@
|
|
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@
|
|
21
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
22
|
|
|
23
23
|
- name: Initialize CodeQL
|
|
24
|
-
uses: github/codeql-action/init@
|
|
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@
|
|
30
|
+
uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
|
31
31
|
|
|
32
32
|
- name: Perform CodeQL Analysis
|
|
33
|
-
uses: github/codeql-action/analyze@
|
|
33
|
+
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
|
34
34
|
with:
|
|
35
35
|
category: "/language:python"
|
{ordercloud_python-2026.6.1 → ordercloud_python-2026.10.2}/.github/workflows/dependency-review.yml
RENAMED
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
name: Review dependencies
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
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@
|
|
18
|
-
- uses: actions/setup-python@
|
|
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
|
-
|
|
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@
|
|
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
|
-
|
|
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@
|
|
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
|
-
|
|
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@
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
20
|
|
|
21
21
|
- name: Generate SBOM
|
|
22
|
-
uses: anchore/sbom-action@
|
|
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@
|
|
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@
|
|
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@
|
|
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.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: ordercloud-python
|
|
3
|
-
Version: 2026.
|
|
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
|
-
- **
|
|
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
|
-
#
|
|
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.
|
|
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
|
-
|
|
512
|
+
803 tests across 12 modules.
|
|
508
513
|
|
|
509
|
-
**Unit tests (
|
|
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` |
|
|
515
|
-
| `test_models.py` |
|
|
516
|
-
| `test_resources.py` |
|
|
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` |
|
|
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` |
|
|
540
|
+
| `auth.py` | 93% |
|
|
536
541
|
| `client.py` | 100% |
|
|
537
|
-
| `config.py` |
|
|
542
|
+
| `config.py` | 94% |
|
|
538
543
|
| `errors.py` | 100% |
|
|
539
|
-
| `http.py` |
|
|
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
|
-
- **
|
|
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
|
-
#
|
|
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.
|
|
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
|
-
|
|
472
|
+
803 tests across 12 modules.
|
|
468
473
|
|
|
469
|
-
**Unit tests (
|
|
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` |
|
|
475
|
-
| `test_models.py` |
|
|
476
|
-
| `test_resources.py` |
|
|
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` |
|
|
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` |
|
|
500
|
+
| `auth.py` | 93% |
|
|
496
501
|
| `client.py` | 100% |
|
|
497
|
-
| `config.py` |
|
|
502
|
+
| `config.py` | 94% |
|
|
498
503
|
| `errors.py` | 100% |
|
|
499
|
-
| `http.py` |
|
|
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.
|
|
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"
|