From c71a49e044878c1301ddc9310a12822a48df67cf Mon Sep 17 00:00:00 2001 From: Peter Braun Date: Fri, 24 Apr 2026 14:35:12 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20do=20not=20include=20secret=20values=20i?= =?UTF-8?q?n=20the=20credentials=20test=20endpoint=20an=E2=80=A6=20(#16425?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: do not include secret values in the credentials test endpoint and add a guard to make sure credentials are testable --- awx/api/views/__init__.py | 10 ++++++---- .../tests/functional/api/test_oidc_credential_test.py | 9 +++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index 66ca03ea8a..e6b476330e 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -1720,12 +1720,10 @@ class OIDCCredentialTestMixin: return {'details': {'sent_jwt_payload': self._decode_jwt_payload_for_display(jwt_token)}} def _call_backend_with_error_handling(self, plugin, backend_kwargs, response_body): - """Call credential backend and handle errors, adding secret_value to response if OIDC details present.""" + """Call credential backend and handle errors.""" try: with set_environ(**settings.AWX_TASK_ENV): - secret_value = plugin.backend(**backend_kwargs) - if 'details' in response_body: - response_body['details']['secret_value'] = secret_value + plugin.backend(**backend_kwargs) return Response(response_body, status=status.HTTP_202_ACCEPTED) except requests.exceptions.HTTPError as exc: message = self._extract_http_error_message(exc) @@ -1791,6 +1789,8 @@ class CredentialExternalTest(OIDCCredentialTestMixin, SubDetailAPIView): It does not support standard credential types such as Machine, SCM, and Cloud."""}) def post(self, request, *args, **kwargs): obj = self.get_object() + if obj.credential_type.kind != 'external': + raise ParseError(_('Credential is not testable.')) backend_kwargs = {} for field_name, value in obj.inputs.items(): backend_kwargs[field_name] = obj.get_input(field_name) @@ -1858,6 +1858,8 @@ class CredentialTypeExternalTest(OIDCCredentialTestMixin, SubDetailAPIView): @extend_schema_if_available(extensions={"x-ai-description": "Test a complete set of input values for an external credential"}) def post(self, request, *args, **kwargs): obj = self.get_object() + if obj.kind != 'external': + raise ParseError(_('Credential type is not testable.')) backend_kwargs = request.data.get('inputs', {}) backend_kwargs.update(request.data.get('metadata', {})) diff --git a/awx/main/tests/functional/api/test_oidc_credential_test.py b/awx/main/tests/functional/api/test_oidc_credential_test.py index 6837d1ca42..5f787632da 100644 --- a/awx/main/tests/functional/api/test_oidc_credential_test.py +++ b/awx/main/tests/functional/api/test_oidc_credential_test.py @@ -257,3 +257,12 @@ def test_credential_type_test_success_returns_jwt_payload(mock_flag, post, admin assert response.status_code == 202 assert 'details' in response.data assert 'sent_jwt_payload' in response.data['details'] + + +@pytest.mark.django_db +def test_credential_external_test_returns_400_for_non_external_credential(post, admin, credential): + # credential fixture creates a non-external credential (e.g. SSH/vault kind) + url = reverse('api:credential_external_test', kwargs={'pk': credential.pk}) + response = post(url, {'metadata': {}}, admin) + assert response.status_code == 400 + assert 'not testable' in response.data.get('detail', '').lower()