[14.0][IMP] currency_rate_update_wise: rename from transferwise + security hardening - #219
[14.0][IMP] currency_rate_update_wise: rename from transferwise + security hardening#219klodr wants to merge 2 commits into
Conversation
…urity hardening Rename the provider after the TransferWise -> Wise rebrand (2021) and apply security fixes from a code audit, on the module that was merged in 14.0 (OCA PR OCA#174). Existing installations get the renamed, hardened module through a plain module update (an OpenUpgrade pre-migration handles the rename). Why keep and update this provider, as a worldwide complement to the ECB provider. The ECB provider is the official European, EUR-centric daily reference; Wise is a global rate source covering currencies and use cases ECB does not: - Rate quality: Wise returns the interbank mid-market rate. Aligned with the ECB fixing on a working day, it tracks the ECB reference markedly closer than xe.com (mean deviation ~0.02% vs ~0.12%, closest to ECB on 25 of 29 currencies). - Worldwide coverage: Wise quotes ~164 currencies against the ECB reference list of 29, including ones ECB omits (e.g. AED, COP). ECB stays the European reference; Wise extends accurate rates to the rest of the world. - Stable JSON API: an authenticated REST endpoint, not HTML scraping like the xe.com provider (which breaks whenever the web page changes). - Targeted requests: we fetch only the currency pairs actually configured, instead of downloading a whole rate table. - History and granularity: the API serves past rates (by timestamp or date range) at day/hour/minute granularity, enabling backfill and corrections. Rename: - module currency_rate_update_transferwise -> currency_rate_update_wise - field res.company.transferwise_api_key -> wise_api_key - provider service value 'TransferWise' -> 'Wise' (label "Wise.com") - API base URL api.transferwise.com -> api.wise.com (/v1/rates endpoint unchanged) - OpenUpgrade pre-migration (update_module_names + rename_columns + UPDATE service) -> no data loss: token, provider records and rate history preserved Security hardening (from audit): - network via requests with a (10, 30)s timeout instead of urllib without any timeout: a cron/worker can no longer hang indefinitely on an unresponsive API - API token restricted with groups="base.group_system" (model + settings + view) and shown with the password widget -> no longer readable by non-admin users - query parameters passed through requests params= (proper encoding) - explicit handling of non-JSON responses (UserError instead of a raw traceback) - robust error detection: isinstance(data, dict) and data.get("error") - ondelete fixed (key is the service value "Wise"; dropped the stray label key) - token storage is an unlimited opaque string, so both the legacy UUID format and the newer JWT format Wise is migrating to are accepted without truncation - legacy-token heads-up: Wise is migrating API access tokens from UUID to JWT, with production issuing JWT from the end-July-2026 transition. During the migration window (2026-08-01 to 2027-08-01) a warning is logged (at Odoo load time and on each scheduled update) when a Wise token still uses the UUID format, inviting regeneration in the Wise Developer Hub. No warning outside that window (before: UUID is the only format; after: migration is over) nor when no key is set. Ref: https://docs.wise.com/guides/developer/auth-and-security/client-credentials-token-migration - tests made hermetic (HTTP mocked, no real network call) + error-response and legacy-token-warning cases Signed-off-by: Claude Perrin <klodr@users.noreply.github.com>
be25d88 to
5a3db5f
Compare
|
@OCA/currency-maintainers when you have a moment, could you please review? This renames |
Wise answers HTTP 400 when the "from" and "to" query parameters are equal: GET /v1/rates?source=USD&target=EUR&from=2026-08-04&to=2026-08-04&group=day -> 400 Bad Request That is exactly the shape of a scheduled run once the rates are up to date: the provider then asks for the single missing day. The failure is therefore intermittent — it only shows up when no more than one day is missing, which is the steady state of a daily cron. Widen the window by one day when it would collapse. The endpoint only returns the days it actually has, so no spurious rate is created; asking for a "to" one day ahead of today answers 200 with today's rate only. The existing tests mock the HTTP layer and never inspect the outgoing query, which is why this went unnoticed. Add a test that captures the parameters and asserts the window is never zero-length. Signed-off-by: Claude Perrin <klodr@users.noreply.github.com> (cherry picked from commit bac73b5)
Note for reviewers: the red CI here is not caused by this PRBoth failures come from the 14.0 branch itself, and both already have a fix
Suggested order: #221, then #220, then this one. Happy to rebase once they |
currency_rate_update_wise (rename of currency_rate_update_transferwise)
TransferWise rebranded to Wise in 2021. This renames the module
currency_rate_update_transferwise→currency_rate_update_wiseand the providerTransferWise→Wise, with identical rate-fetching functionality.res_currency_rate_provider_Wise.py.migrations/14.0.2.0.0/pre-migration.pymigrates existingres.currency.rate.providerrecords (serviceTransferWise→Wise) and the relatedir.model.data, so existing configurations keep working after a plain module update.base.group_system.See the commit message for the full rationale (Wise vs ECB coverage, UUID→JWT token transition).
Migrations to 15.0–18.0 will follow in dedicated PRs.