From d452098123bbea0da5d9a2e3779e2dd61d4c65a1 Mon Sep 17 00:00:00 2001 From: Andrew Potozniak Date: Wed, 30 Jul 2025 13:55:22 -0400 Subject: [PATCH] [AAP-50446] Error handling enhancements and GATEWAY_BASE_URL override (#7037) * Added better error handling and messaging when the service token authentication is broken. Allowed for GATEWAY_BASE_URL to override the service token's base url if it is set in the environment variables. Co-Authored-By: Cursor (claude-4-sonnet) * Removed GATEWAY_BASE_URL override for service token auth. --- .../commands/import_auth_config_to_gateway.py | 8 ++++ .../test_import_auth_config_to_gateway.py | 41 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/awx/main/management/commands/import_auth_config_to_gateway.py b/awx/main/management/commands/import_auth_config_to_gateway.py index 726a7b86b0..f89ebf3496 100644 --- a/awx/main/management/commands/import_auth_config_to_gateway.py +++ b/awx/main/management/commands/import_auth_config_to_gateway.py @@ -103,6 +103,14 @@ class Command(BaseCommand): self.stdout.write(self.style.SUCCESS(f'Skip SSL Verification: {not resource_api_client.verify_https}')) self.stdout.write(self.style.SUCCESS(f'Connection Validated: {response.status_code == 200}')) + if response.status_code != 200: + self.stdout.write( + self.style.ERROR( + f'Gateway Service Token is unable to connect to Gateway via the base URL {resource_api_client.base_url}. Recieved HTTP response code {response.status_code}' + ) + ) + sys.exit(1) + # Create Gateway client and run migrations try: self.stdout.write(self.style.SUCCESS('\n=== Connecting to Gateway ===')) diff --git a/awx/main/tests/unit/commands/test_import_auth_config_to_gateway.py b/awx/main/tests/unit/commands/test_import_auth_config_to_gateway.py index 6d1563c8ea..cfb7e64ac5 100644 --- a/awx/main/tests/unit/commands/test_import_auth_config_to_gateway.py +++ b/awx/main/tests/unit/commands/test_import_auth_config_to_gateway.py @@ -189,7 +189,7 @@ class TestImportAuthConfigToGatewayCommand(TestCase): self.assertIn('mappers', output) self.assertIn('settings', output) - @patch.dict(os.environ, {'GATEWAY_SKIP_VERIFY': 'false'}, clear=False) # Ensure verify_https=True + @patch.dict(os.environ, {'GATEWAY_SKIP_VERIFY': 'false'}, clear=True) # Ensure verify_https=True @patch('awx.main.management.commands.import_auth_config_to_gateway.create_api_client') @patch('awx.main.management.commands.import_auth_config_to_gateway.GatewayClientSVCToken') @patch('awx.main.management.commands.import_auth_config_to_gateway.urlparse') @@ -540,3 +540,42 @@ class TestImportAuthConfigToGatewayCommand(TestCase): mock_gateway_client.reset_mock() mock_stdout.seek(0) mock_stdout.truncate(0) + + @patch.dict(os.environ, {'GATEWAY_SKIP_VERIFY': 'false'}) + @patch('awx.main.management.commands.import_auth_config_to_gateway.create_api_client') + @patch('awx.main.management.commands.import_auth_config_to_gateway.urlparse') + @patch('awx.main.management.commands.import_auth_config_to_gateway.urlunparse') + @patch('awx.main.management.commands.import_auth_config_to_gateway.SettingsMigrator') + @patch('sys.stdout', new_callable=StringIO) + def test_service_token_connection_validation_failure(self, mock_stdout, mock_settings_migrator, mock_urlunparse, mock_urlparse, mock_create_api_client): + """Test that non-200 response from get_service_metadata causes error exit.""" + # Mock resource API client with failing response + mock_resource_client = Mock() + mock_resource_client.base_url = 'https://gateway.example.com/api/v1' + mock_resource_client.jwt_user_id = 'test-user' + mock_resource_client.jwt_expiration = '2024-12-31' + mock_resource_client.verify_https = True + mock_response = Mock() + mock_response.status_code = 401 # Simulate unauthenticated error + mock_resource_client.get_service_metadata.return_value = mock_response + mock_create_api_client.return_value = mock_resource_client + + # Mock URL parsing (needed for the service token flow) + mock_parsed = Mock() + mock_parsed.scheme = 'https' + mock_parsed.netloc = 'gateway.example.com' + mock_urlparse.return_value = mock_parsed + mock_urlunparse.return_value = 'https://gateway.example.com/' + + with patch.object(self.command, 'stdout', mock_stdout): + with pytest.raises(SystemExit) as exc_info: + self.command.handle(**self.options_svc_token_skip_all()) + # Should exit with code 1 for connection failure + assert exc_info.value.code == 1 + + # Verify error message is displayed + output = mock_stdout.getvalue() + self.assertIn( + 'Gateway Service Token is unable to connect to Gateway via the base URL https://gateway.example.com/. Recieved HTTP response code 401', output + ) + self.assertIn('Connection Validated: False', output)