Skip to content

feat(box): upgrade SDK to 2.0.0, add pytest unit tests#277

Open
Shubhank-Jonnada wants to merge 6 commits into
masterfrom
worktree-agent-afaab30f86b04922c
Open

feat(box): upgrade SDK to 2.0.0, add pytest unit tests#277
Shubhank-Jonnada wants to merge 6 commits into
masterfrom
worktree-agent-afaab30f86b04922c

Conversation

@Shubhank-Jonnada
Copy link
Copy Markdown
Contributor

@Shubhank-Jonnada Shubhank-Jonnada commented Apr 28, 2026

Summary

  • Upgrades autohive-integrations-sdk pin from ~=1.0.2 to ~=2.0.0 in box/requirements.txt
  • Updates all context.fetch() call sites to access .data on the returned FetchResponse object
  • Converts all error returns to ActionError(message=...)
  • Converts all success returns to ActionResult(data=..., cost_usd=0.0)
  • Removes legacy "error" and "result" boolean fields from output schemas in config.json
  • Bumps config.json version from 0.0.1 to 2.0.0
  • Adds box/tests/conftest.py and box/tests/test_box_unit.py with unit coverage for all 5 actions
  • Replaces the legacy test context shim with modern pytest fixtures
  • Modernizes box/tests/test_box_integration.py to use env_credentials, make_context, FetchResponse, and platform OAuth-style BOX_ACCESS_TOKEN
  • Documents the Box token extraction recipe in the live test header

Auth/test alignment

Box is configured as platform OAuth in config.json:

{"type": "platform", "provider": "box"}

The live tests now match that shape:

  • env var: BOX_ACCESS_TOKEN
  • request header: Authorization: Bearer <token>
  • context auth: {"auth_type": "PlatformOauth2", "credentials": {"access_token": token}}

Integration test coverage

Safe read-only live coverage currently includes:

  • list_shared_folders
  • list_files
  • list_folder_contents
  • get_file via a file discovered from list_files when one exists

Issue #295 remains open for broader/destructive live coverage because this PR does not add a safe upload lifecycle/cleanup flow.

Safe read-only command:

pytest box/tests/test_box_integration.py -m "integration and not destructive"

Test plan

  • .venv/bin/python -m pytest box/tests -m unit -q — 32 passed
  • .venv/bin/python -m pytest box/tests/test_box_integration.py -m "integration and not destructive" -q — 4 skipped without live Box creds
  • .venv/bin/python -m pytest box/ -q — 32 passed; integration file not collected by default
  • .venv/bin/python ../autohive-integrations-tooling/scripts/validate_integration.py box — passed
  • .venv/bin/python ../autohive-integrations-tooling/scripts/check_code.py box — passed

- Bump autohive-integrations-sdk pin to ~=2.0.0
- Update all context.fetch() return values to access .data
- Convert all error returns to ActionError(message=...)
- Convert all success returns to ActionResult(data=..., cost_usd=0.0)
- Remove "error" and "result" boolean fields from output schemas
- Bump config.json version to 2.0.0
- Add box/tests/conftest.py and box/tests/test_box_unit.py (32 unit tests)
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

🔍 Integration Validation Results

Commit: 72b41d1b744615a2ee456539c216d3aa2a6d15b9 · feat(count): add Count accounting integration with 43 actions
Updated: 2026-05-12T05:51:08Z

Changed directories: box count

Check Result
Structure ✅ Passed
Code ❌ Failed
Tests ❌ Failed
README ✅ Passed
Version ✅ Passed
✅ Structure Check output
Validating 2 integration(s)...

============================================================
Integration: box
============================================================
✅ All checks passed!

============================================================
Integration: count
============================================================
✅ All checks passed!

============================================================
SUMMARY
============================================================
Integrations validated: 2
Total errors: 0
Total warnings: 0

✅ All validations passed!
❌ Code Check output

[notice] A new release of pip is available: 26.0.1 -> 26.1.1
[notice] To update, run: pip install --upgrade pip

[notice] A new release of pip is available: 26.0.1 -> 26.1.1
[notice] To update, run: pip install --upgrade pip
----------------------------------------
Checking: box
----------------------------------------

📦 Installing dependencies...

🐍 Checking Python syntax...
   ✅ Syntax OK

📥 Checking imports...
   ✅ Imports OK

📄 Checking JSON files...
   ✅ JSON files OK

🔍 Linting with ruff...
   ✅ Lint OK

🎨 Checking formatting with ruff...
   ✅ Formatting OK

🔒 Scanning for security issues with bandit...
   ✅ Security OK

🛡️ Checking dependencies for vulnerabilities with pip-audit...
   ✅ Dependencies OK

🔗 Checking config-code sync...
   ✅ Config-code sync OK

🔄 Checking fetch patterns...
   ✅ Fetch patterns OK

----------------------------------------
Checking: count
----------------------------------------

📦 Installing dependencies...

🐍 Checking Python syntax...
   ✅ Syntax OK

📥 Checking imports...
   ✅ Imports OK

📄 Checking JSON files...
   ✅ JSON files OK

🔍 Linting with ruff...
   ✅ Lint OK

🎨 Checking formatting with ruff...
   ✅ Formatting OK

🔒 Scanning for security issues with bandit...
   ✅ Security OK

🛡️ Checking dependencies for vulnerabilities with pip-audit...
   ✅ Dependencies OK

🔗 Checking config-code sync...
   ⚠️  Action 'list_accounts': parameter 'limit' defined in input_schema but never accessed in code
   ⚠️  Action 'list_accounts': parameter 'page' defined in input_schema but never accessed in code
   ⚠️  Action 'create_account': parameter 'type' defined in input_schema but never accessed in code
   ⚠️  Action 'create_account': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'create_account': parameter 'code' defined in input_schema but never accessed in code
   ⚠️  Action 'update_account': parameter 'type' defined in input_schema but never accessed in code
   ⚠️  Action 'update_account': parameter 'code' defined in input_schema but never accessed in code
   ⚠️  Action 'update_account': parameter 'account_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'update_account': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'list_customers': parameter 'search' defined in input_schema but never accessed in code
   ⚠️  Action 'list_customers': parameter 'limit' defined in input_schema but never accessed in code
   ⚠️  Action 'list_customers': parameter 'orderDirection' defined in input_schema but never accessed in code
   ⚠️  Action 'list_customers': parameter 'orderBy' defined in input_schema but never accessed in code
   ⚠️  Action 'list_customers': parameter 'page' defined in input_schema but never accessed in code
   ⚠️  Action 'create_customer': parameter 'notes' defined in input_schema but never accessed in code
   ⚠️  Action 'create_customer': parameter 'phone' defined in input_schema but never accessed in code
   ⚠️  Action 'create_customer': parameter 'email' defined in input_schema but never accessed in code
   ⚠️  Action 'create_customer': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'create_customer': parameter 'website' defined in input_schema but never accessed in code
   ⚠️  Action 'update_customer': parameter 'phone' defined in input_schema but never accessed in code
   ⚠️  Action 'update_customer': parameter 'notes' defined in input_schema but never accessed in code
   ⚠️  Action 'update_customer': parameter 'email' defined in input_schema but never accessed in code
   ⚠️  Action 'update_customer': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'update_customer': parameter 'customer_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'update_customer': parameter 'website' defined in input_schema but never accessed in code
   ⚠️  Action 'list_vendors': parameter 'search' defined in input_schema but never accessed in code
   ⚠️  Action 'list_vendors': parameter 'limit' defined in input_schema but never accessed in code
   ⚠️  Action 'list_vendors': parameter 'page' defined in input_schema but never accessed in code
   ⚠️  Action 'create_vendor': parameter 'phone' defined in input_schema but never accessed in code
   ⚠️  Action 'create_vendor': parameter 'email' defined in input_schema but never accessed in code
   ⚠️  Action 'create_vendor': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'create_vendor': parameter 'taxNumber' defined in input_schema but never accessed in code
   ⚠️  Action 'create_vendor': parameter 'website' defined in input_schema but never accessed in code
   ⚠️  Action 'update_vendor': parameter 'phone' defined in input_schema but never accessed in code
   ⚠️  Action 'update_vendor': parameter 'email' defined in input_schema but never accessed in code
   ⚠️  Action 'update_vendor': parameter 'vendor_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'update_vendor': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'update_vendor': parameter 'website' defined in input_schema but never accessed in code
   ⚠️  Action 'list_products': parameter 'search' defined in input_schema but never accessed in code
   ⚠️  Action 'list_products': parameter 'limit' defined in input_schema but never accessed in code
   ⚠️  Action 'list_products': parameter 'page' defined in input_schema but never accessed in code
   ⚠️  Action 'create_product': parameter 'description' defined in input_schema but never accessed in code
   ⚠️  Action 'create_product': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'create_product': parameter 'price' defined in input_schema but never accessed in code
   ⚠️  Action 'create_product': parameter 'type' defined in input_schema but never accessed in code
   ⚠️  Action 'update_product': parameter 'description' defined in input_schema but never accessed in code
   ⚠️  Action 'update_product': parameter 'price' defined in input_schema but never accessed in code
   ⚠️  Action 'update_product': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'update_product': parameter 'product_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'list_transactions': parameter 'limit' defined in input_schema but never accessed in code
   ⚠️  Action 'list_transactions': parameter 'startDate' defined in input_schema but never accessed in code
   ⚠️  Action 'list_transactions': parameter 'page' defined in input_schema but never accessed in code
   ⚠️  Action 'list_transactions': parameter 'endDate' defined in input_schema but never accessed in code
   ⚠️  Action 'create_transaction': parameter 'description' defined in input_schema but never accessed in code
   ⚠️  Action 'create_transaction': parameter 'date' defined in input_schema but never accessed in code
   ⚠️  Action 'create_transaction': parameter 'amount' defined in input_schema but never accessed in code
   ⚠️  Action 'create_transaction': parameter 'accountUuid' defined in input_schema but never accessed in code
   ⚠️  Action 'update_transaction': parameter 'description' defined in input_schema but never accessed in code
   ⚠️  Action 'update_transaction': parameter 'transaction_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'update_transaction': parameter 'date' defined in input_schema but never accessed in code
   ⚠️  Action 'update_transaction': parameter 'amount' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'notes' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'tagUuids' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'date' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'products' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'invoiceType' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'invoiceNumber' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'customerUuid' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'dueDate' defined in input_schema but never accessed in code
   ⚠️  Action 'create_invoice': parameter 'isDraft' defined in input_schema but never accessed in code
   ⚠️  Action 'update_invoice': parameter 'invoice_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'update_invoice': parameter 'notes' defined in input_schema but never accessed in code
   ⚠️  Action 'update_invoice': parameter 'dueDate' defined in input_schema but never accessed in code
   ⚠️  Action 'update_invoice': parameter 'isDraft' defined in input_schema but never accessed in code
   ⚠️  Action 'create_bill': parameter 'notes' defined in input_schema but never accessed in code
   ⚠️  Action 'create_bill': parameter 'billNumber' defined in input_schema but never accessed in code
   ⚠️  Action 'create_bill': parameter 'date' defined in input_schema but never accessed in code
   ⚠️  Action 'create_bill': parameter 'products' defined in input_schema but never accessed in code
   ⚠️  Action 'create_bill': parameter 'dueDate' defined in input_schema but never accessed in code
   ⚠️  Action 'create_bill': parameter 'vendorUuid' defined in input_schema but never accessed in code
   ⚠️  Action 'update_bill': parameter 'notes' defined in input_schema but never accessed in code
   ⚠️  Action 'update_bill': parameter 'dueDate' defined in input_schema but never accessed in code
   ⚠️  Action 'update_bill': parameter 'bill_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'list_journal_entries': parameter 'limit' defined in input_schema but never accessed in code
   ⚠️  Action 'list_journal_entries': parameter 'startDate' defined in input_schema but never accessed in code
   ⚠️  Action 'list_journal_entries': parameter 'page' defined in input_schema but never accessed in code
   ⚠️  Action 'list_journal_entries': parameter 'endDate' defined in input_schema but never accessed in code
   ⚠️  Action 'create_journal_entry': parameter 'lines' defined in input_schema but never accessed in code
   ⚠️  Action 'create_journal_entry': parameter 'description' defined in input_schema but never accessed in code
   ⚠️  Action 'create_journal_entry': parameter 'date' defined in input_schema but never accessed in code
   ⚠️  Action 'update_journal_entry': parameter 'description' defined in input_schema but never accessed in code
   ⚠️  Action 'update_journal_entry': parameter 'date' defined in input_schema but never accessed in code
   ⚠️  Action 'update_journal_entry': parameter 'journal_entry_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'list_tags': parameter 'limit' defined in input_schema but never accessed in code
   ⚠️  Action 'list_tags': parameter 'page' defined in input_schema but never accessed in code
   ⚠️  Action 'create_tag': parameter 'color' defined in input_schema but never accessed in code
   ⚠️  Action 'create_tag': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'update_tag': parameter 'color' defined in input_schema but never accessed in code
   ⚠️  Action 'update_tag': parameter 'name' defined in input_schema but never accessed in code
   ⚠️  Action 'update_tag': parameter 'tag_uuid' defined in input_schema but never accessed in code
   ⚠️  Action 'get_trial_balance': parameter 'startDate' defined in input_schema but never accessed in code
   ⚠️  Action 'get_trial_balance': parameter 'endDate' defined in input_schema but never accessed in code
   ⚠️  Action 'get_balance_sheet': parameter 'date' defined in input_schema but never accessed in code
   ⚠️  Action 'get_profit_and_loss': parameter 'startDate' defined in input_schema but never accessed in code
   ⚠️  Action 'get_profit_and_loss': parameter 'endDate' defined in input_schema but never accessed in code
   ✅ Config-code sync OK

🔄 Checking fetch patterns...
   SDK 2.x requires using response.data to access the response body. context.fetch() now returns a FetchResponse object.
     count/count.py:
       Line 46: isinstance(resp, ...) — use isinstance(resp.data, ...) with SDK 2.x
       Line 46: resp.get(...) — use resp.data.get(...) with SDK 2.x
   ❌ Fetch pattern issues found

   Fix: SDK 2.x returns FetchResponse — use response.data to access the body

========================================
❌ CODE CHECK FAILED
========================================
❌ Tests Check output

Integration   Tests  Coverage        Status
-------------------------------------------
box       32/32       95%      ✅ Passed
count       0/0       36%      ❌ Failed
-------------------------------------------
Total     32/32           ❌ Some failed

============================================================
  count — failure detail
============================================================

================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________

Name             Stmts   Miss  Cover   Missing
----------------------------------------------
count/count.py     386    247    36%   14-28, 38-42, 46, 52-57, 63-67, 73-78, 84-88, 94-99, 105-109, 115-119, 125-129, 135-140, 146-150, 156-161, 167-171, 177-182, 188-192, 198-203, 209-213, 219-223, 229-233, 239-244, 250-254, 260-265, 271-275, 281-286, 292-296, 302-306, 312-316, 322-327, 333-337, 343-347, 353-358, 364-368, 374-378, 384-389, 395-399, 405-410, 416-420, 426-431, 437-441, 447-452, 458-462, 468-473, 479-484, 490-495
----------------------------------------------
TOTAL              388    247    36%

1 file skipped due to complete coverage.
44 deselected in 0.22s


❌ Tests failed: count
✅ README Check output
========================================
✅ README CHECK PASSED
========================================
✅ Version Check output
✅ box: 0.0.1 → 2.0.0 (major bump)
✅ count: New integration with version 1.0.0

========================================
✅ VERSION CHECK PASSED
========================================

TheRealAgentK
TheRealAgentK previously approved these changes Apr 29, 2026
Copy link
Copy Markdown
Collaborator

@TheRealAgentK TheRealAgentK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. SDK 2.0.0 migration is clean — context.fetch().data, ActionError(message=...) everywhere, schema envelope fields removed, version bumped from 0.0.12.0.0. 32 unit tests across all 5 actions.

Local CI verified: validate_integration ✅, check_code ✅, ruff ✅, pytest ✅.

Follow-up tracked in #295 — please add a test_box_integration.py in a follow-up PR. Not blocking this merge.

Process nit: branch worktree-agent-* doesn't follow <type>/<issue#>/<desc> per AGENTS.md. Please follow the convention next time.

…ytest integration tests

- Add pageToken support to list_files and list_folder_contents to silence
  config-code sync warnings
- Replace manual asyncio test_box.py with pytest-style test_box_integration.py
- Add BOX_ACCESS_TOKEN to .env.example
Copy link
Copy Markdown
Collaborator

@TheRealAgentK TheRealAgentK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-approved to remove the block, needs 3rd party review and then e-2-e test runs.

@TheRealAgentK
Copy link
Copy Markdown
Collaborator

@Shubhank-Jonnada One finding when I ran an agentic review against the final PR was:

Blocking finding

Pagination is implemented with the wrong Box API contract

list_files and list_folder_contents now accept/use pageToken, but they send it as marker and only emit nextPageToken when the response contains next_marker.

That does not match Box’s APIs:

  • GET /search uses offset / limit; it does not use marker.
  • GET /folders/:id/items is offset-based by default. Marker pagination only works if usemarker=true is also sent.
  • Current code therefore won’t reliably page beyond the first page, and the new tests validate the wrong next_marker behavior.

Affected locations:

  • list_files sends marker for search/root folder requests and only reads next_marker
  • list_folder_contents sends marker without usemarker=true and only reads next_marker
  • list_folder_contents also reuses the parent params for recursive subfolder fetches, so a parent pageToken would incorrectly be applied to every subfolder request too.

Recommended fix: keep it simple and use the same offset pattern already used by list_shared_folders: send offset, compute nextPageToken from total_count, current offset, and pageSize. For recursive subfolder calls, build fresh params without inheriting the parent page token.

The corresponding tests should be updated too; the current unit tests around next_marker for these actions encode the broken behavior.

It was introduced in your second original commit.

Could you please double-check the correctness of the integration code before finalising this?

Copy link
Copy Markdown
Collaborator

@TheRealAgentK TheRealAgentK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See last comment, there might be a pagination issue here.

@Shubhank-Jonnada
Copy link
Copy Markdown
Contributor Author

✅ Live Integration Tests — Box (5/5 actions)

All 5 actions verified against the live Box API:

# Action Test Result
1 list_shared_folders test_list_shared_folders ✅ Pass
2 list_files test_list_files ✅ Pass
3 list_folder_contents test_list_folder_contents ✅ Pass
4 get_file test_get_file ✅ Pass
5 upload_file test_upload_file ✅ Pass

5 passed, 0 failed — full end-to-end coverage across all actions.

Also fixed: import path from box import boxfrom box.box import box (was causing ImportError).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants