diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000..ba343211 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +odoo-addon-webservice @ git+https://github.com/OCA/web-api.git@refs/pull/143/head#subdirectory=webservice +odoo-addon-webservice_server_env @ git+https://github.com/OCA/web-api.git@refs/pull/143/head#subdirectory=webservice_server_env diff --git a/webservice/README.rst b/webservice/README.rst index a01025ef..0155b1a4 100644 --- a/webservice/README.rst +++ b/webservice/README.rst @@ -43,6 +43,13 @@ HTTP call returns by default the content of the response. A context .. contents:: :local: +Configuration +============= + +When a database is neutralized, stored webservice backend credentials +(username, password, API key, OAuth2 client id/secret/token, custom +OAuth2 auth header value) are cleared. + Bug Tracker =========== diff --git a/webservice/data/neutralize.sql b/webservice/data/neutralize.sql new file mode 100644 index 00000000..264b1b17 --- /dev/null +++ b/webservice/data/neutralize.sql @@ -0,0 +1,9 @@ +-- remove webservice backend credentials +UPDATE webservice_backend + SET username = NULL, + password = NULL, + api_key = NULL, + oauth2_clientid = NULL, + oauth2_client_secret = NULL, + oauth2_client_auth_value = NULL, + oauth2_token = NULL; diff --git a/webservice/readme/CONFIGURE.md b/webservice/readme/CONFIGURE.md new file mode 100644 index 00000000..62002601 --- /dev/null +++ b/webservice/readme/CONFIGURE.md @@ -0,0 +1,3 @@ +When a database is neutralized, stored webservice backend credentials +(username, password, API key, OAuth2 client id/secret/token, custom +OAuth2 auth header value) are cleared. diff --git a/webservice/static/description/index.html b/webservice/static/description/index.html index ebcfdd44..f5fcfc3b 100644 --- a/webservice/static/description/index.html +++ b/webservice/static/description/index.html @@ -382,17 +382,24 @@

WebService

Table of contents

+
+

Configuration

+

When a database is neutralized, stored webservice backend credentials +(username, password, API key, OAuth2 client id/secret/token, custom +OAuth2 auth header value) are cleared.

+
-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -400,23 +407,23 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association diff --git a/webservice/tests/__init__.py b/webservice/tests/__init__.py index 70d7ce42..88a07b8f 100644 --- a/webservice/tests/__init__.py +++ b/webservice/tests/__init__.py @@ -1,3 +1,4 @@ from . import test_oauth2 from . import test_webservice from . import test_utils +from . import test_neutralize diff --git a/webservice/tests/test_neutralize.py b/webservice/tests/test_neutralize.py new file mode 100644 index 00000000..e1e10959 --- /dev/null +++ b/webservice/tests/test_neutralize.py @@ -0,0 +1,49 @@ +# Copyright 2026 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.modules import neutralize +from odoo.tests import tagged + +from .common import CommonWebService + + +@tagged("neutralize") +class TestWebserviceNeutralize(CommonWebService): + @classmethod + def _setup_records(cls): + res = super()._setup_records() + # `auth_type="none"` skips the `_check_auth_type` constraint so all + # credential fields can be populated at once regardless of which + # auth method would normally require them. + cls.backend = cls.env["webservice.backend"].create( + { + "name": "Neutralize WebService", + "protocol": "http", + "url": "https://localhost.demo.odoo/", + "tech_name": "neutralize_ws", + "auth_type": "none", + "username": "secret-user", + "password": "secret-password", + "api_key": "secret-api-key", + "oauth2_clientid": "secret-client-id", + "oauth2_client_secret": "secret-client-secret", + "oauth2_client_auth_value": "secret-header-value", + "oauth2_token": '{"access_token": "secret-token"}', + } + ) + return res + + def test_neutralize_removes_webservice_credentials(self): + """Test database neutralization clears stored webservice backend credentials.""" + installed_modules = neutralize.get_installed_modules(self.cr) + queries = neutralize.get_neutralization_queries(installed_modules) + for query in queries: + self.cr.execute(query) + self.backend.invalidate_recordset() + self.assertFalse(self.backend.username) + self.assertFalse(self.backend.password) + self.assertFalse(self.backend.api_key) + self.assertFalse(self.backend.oauth2_clientid) + self.assertFalse(self.backend.oauth2_client_secret) + self.assertFalse(self.backend.oauth2_client_auth_value) + self.assertFalse(self.backend.oauth2_token) diff --git a/webservice_server_env/README.rst b/webservice_server_env/README.rst index 657979b9..35d7bb6e 100644 --- a/webservice_server_env/README.rst +++ b/webservice_server_env/README.rst @@ -40,6 +40,14 @@ Webservice addon. .. contents:: :local: +Configuration +============= + +When a database is neutralized, webservice backend credentials +(username, password, API key, OAuth2 client id/secret, custom OAuth2 +auth header value) stored as server environment defaults are cleared as +well. + Bug Tracker =========== diff --git a/webservice_server_env/data/neutralize.sql b/webservice_server_env/data/neutralize.sql new file mode 100644 index 00000000..ae619e29 --- /dev/null +++ b/webservice_server_env/data/neutralize.sql @@ -0,0 +1,16 @@ +-- remove webservice backend credentials stored as server environment defaults +-- (this module turns username/password/api_key/oauth2_clientid/oauth2_client_secret +-- into non-stored fields backed by the server_env_defaults JSON column +-- this neutralization is needed if both webservice and server_environment are installed, +-- so the plain columns nulled by webservice/data/neutralize.sql can be properly cleared) +UPDATE webservice_backend + SET server_env_defaults = ( + server_env_defaults::jsonb + - 'x_username_env_default' + - 'x_password_env_default' + - 'x_api_key_env_default' + - 'x_oauth2_clientid_env_default' + - 'x_oauth2_client_secret_env_default' + - 'x_oauth2_client_auth_value_env_default' + )::text + WHERE server_env_defaults IS NOT NULL; diff --git a/webservice_server_env/readme/CONFIGURE.md b/webservice_server_env/readme/CONFIGURE.md new file mode 100644 index 00000000..6c80484f --- /dev/null +++ b/webservice_server_env/readme/CONFIGURE.md @@ -0,0 +1,3 @@ +When a database is neutralized, webservice backend credentials (username, +password, API key, OAuth2 client id/secret, custom OAuth2 auth header +value) stored as server environment defaults are cleared as well. diff --git a/webservice_server_env/static/description/index.html b/webservice_server_env/static/description/index.html index 053d2fa2..69aa880a 100644 --- a/webservice_server_env/static/description/index.html +++ b/webservice_server_env/static/description/index.html @@ -380,17 +380,25 @@

WebService Server Environment

Table of contents

+
+

Configuration

+

When a database is neutralized, webservice backend credentials +(username, password, API key, OAuth2 client id/secret, custom OAuth2 +auth header value) stored as server environment defaults are cleared as +well.

+
-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -398,23 +406,23 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Creu Blanca
  • Camptocamp
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association diff --git a/webservice_server_env/tests/__init__.py b/webservice_server_env/tests/__init__.py index 38fb5cf0..e228ba19 100644 --- a/webservice_server_env/tests/__init__.py +++ b/webservice_server_env/tests/__init__.py @@ -1 +1,2 @@ from . import test_oauth2 +from . import test_neutralize diff --git a/webservice_server_env/tests/test_neutralize.py b/webservice_server_env/tests/test_neutralize.py new file mode 100644 index 00000000..906630e0 --- /dev/null +++ b/webservice_server_env/tests/test_neutralize.py @@ -0,0 +1,47 @@ +# Copyright 2026 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.modules import neutralize +from odoo.tests import tagged + +from odoo.addons.webservice.tests.common import CommonWebService + + +@tagged("neutralize") +class TestWebserviceServerEnvNeutralize(CommonWebService): + @classmethod + def _setup_records(cls): + res = super()._setup_records() + # No `SERVER_ENV_CONFIG` section is defined for this tech_name, so + # these credentials are stored as env-default values inside + # `server_env_defaults` instead of the (now unused) plain columns. + cls.backend = cls.env["webservice.backend"].create( + { + "name": "Neutralize WebService Server Env", + "protocol": "http", + "url": "https://localhost.demo.odoo/", + "tech_name": "neutralize_server_env_ws", + "auth_type": "none", + "username": "secret-user", + "password": "secret-password", + "api_key": "secret-api-key", + "oauth2_clientid": "secret-client-id", + "oauth2_client_secret": "secret-client-secret", + "oauth2_client_auth_value": "secret-header-value", + } + ) + return res + + def test_neutralize_removes_server_env_default_credentials(self): + """Test neutralization clears credentials stored as server-env defaults.""" + installed_modules = neutralize.get_installed_modules(self.cr) + queries = neutralize.get_neutralization_queries(installed_modules) + for query in queries: + self.cr.execute(query) + self.backend.invalidate_recordset() + self.assertFalse(self.backend.username) + self.assertFalse(self.backend.password) + self.assertFalse(self.backend.api_key) + self.assertFalse(self.backend.oauth2_clientid) + self.assertFalse(self.backend.oauth2_client_secret) + self.assertFalse(self.backend.oauth2_client_auth_value)