diff --git a/README.md b/README.md index 15a7c30..dffd2db 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@ hatch run test:integration ``` Note: integration tests cannot currently be invoked by running `pytest tests/integration` because `PYTHONPATH` is not set correctly in that case. +The integration tests test a live, deployed API and point the API at real web resources that are provisioned for testing purposes. The integration test content is currently hosted on `caatestsuite.com` (maintained by SSLMate) and `integration-testing.open-mpic.org` (maintained by the maintainers of the Open MPIC project). The zone file for `caatestsuite.com` can be found [here](https://github.com/SSLMate/caatestsuite) along with more info about the tests at [caatestsuite.com](https://caatestsuite.com), and the zone file for `integration-testing.open-mpic.org` can be found [here](https://github.com/open-mpic/open-mpic-integration-zone). Both of these services are maintained on a best-effort basis. If there is an issue with integration tests, check the availability of these two services and the responses from the sub-domains used in the integration tests. THESE SERVICES ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. They are not intended for use outside of development integration testing (i.e., no excessive query volume, no use in production systems). + If you encounter issues running integration tests with the above commands, contact the project maintainers. @@ -93,9 +95,8 @@ After `tofu destroy`, `./clean.sh` in the root directory also clears generated/z # Remaining tasks -The Open MPIC project is currently under development. The pre-alpha release includes support for the HTTP and DNS domain validation methods using Amazon Web Services Lambda and API Gateway. The work items remaining to a feature-complete production-level product include the following: (subject to change) +The Open MPIC project is currently under development. The work items remaining to a feature-complete production-level product include the following: (subject to change) -- Full alighnment with API spec v2 - Additional integration testing Throughout the development process, we will address any GitHub issues raised, and may modify the API accordingly. We also welcome pull requests from the general community. diff --git a/tests/integration/test_deployed_mpic_api.py b/tests/integration/test_deployed_mpic_api.py index 42777cf..653febd 100644 --- a/tests/integration/test_deployed_mpic_api.py +++ b/tests/integration/test_deployed_mpic_api.py @@ -3,10 +3,11 @@ import pytest from pydantic import TypeAdapter -from open_mpic_core.common_domain.check_parameters import CaaCheckParameters, DcvWebsiteChangeValidationDetails +from open_mpic_core.common_domain.check_parameters import CaaCheckParameters, DcvWebsiteChangeValidationDetails, DcvAcmeDns01ValidationDetails, DcvDnsChangeValidationDetails from open_mpic_core.common_domain.check_parameters import DcvCheckParameters from open_mpic_core.common_domain.enum.certificate_type import CertificateType from open_mpic_core.common_domain.enum.check_type import CheckType +from open_mpic_core.common_domain.enum.dns_record_type import DnsRecordType from open_mpic_core.mpic_coordinator.domain.mpic_request import MpicCaaRequest from open_mpic_core.mpic_coordinator.domain.mpic_request import MpicDcvRequest from open_mpic_core.mpic_coordinator.domain.mpic_orchestration_parameters import MpicRequestOrchestrationParameters @@ -141,23 +142,73 @@ def api_should_return_is_valid_false_for_do_not_issue_caa_test_suite_for_rfc_684 mpic_response = self.mpic_response_adapter.validate_json(response.text) assert mpic_response.is_valid is False - @pytest.mark.skip(reason='Not implemented yet') - def api_should_return_200_given_valid_dcv_validation(self, api_client): + @pytest.mark.parametrize('domain_or_ip_target, purpose_of_test', [ + ('dns-01.integration-testing.open-mpic.org', 'Standard proper dns-01 test'), + ('dns-01-multi.integration-testing.open-mpic.org', 'Proper dns-01 test with multiple TXT records'), + ('dns-01-cname.integration-testing.open-mpic.org', 'Proper dns-01 test with CNAME') + ]) + def api_should_return_200_given_valid_dns_01_validation(self, api_client, domain_or_ip_target, purpose_of_test): + print(f"Running test for {domain_or_ip_target} ({purpose_of_test})") request = MpicDcvRequest( - domain_or_ip_target='example.com', + domain_or_ip_target=domain_or_ip_target, orchestration_parameters=MpicRequestOrchestrationParameters(perspective_count=3, quorum_count=2), dcv_check_parameters=DcvCheckParameters( - validation_details=DcvWebsiteChangeValidationDetails(http_token_path='/', - challenge_value='test') + validation_details=DcvAcmeDns01ValidationDetails(key_authorization="7FwkJPsKf-TH54wu4eiIFA3nhzYaevsL7953ihy-tpo") ) ) print("\nRequest:\n", json.dumps(request.model_dump(), indent=4)) # pretty print request body response = api_client.post(MPIC_REQUEST_PATH, json.dumps(request.model_dump())) assert response.status_code == 200 - response_body = json.loads(response.text) - print("\nResponse:\n", json.dumps(response_body, indent=4)) # pretty print response body - # finish test... (and figure out how to actually run it successfully and reliably) + mpic_response = self.mpic_response_adapter.validate_json(response.text) + + assert mpic_response.is_valid is True + + @pytest.mark.parametrize('domain_or_ip_target, purpose_of_test', [ + ('dns-01-leading-whitespace.integration-testing.open-mpic.org', 'leading whitespace'), + ('dns-01-trailing-whitespace.integration-testing.open-mpic.org', 'trailing'), + ('dns-01-nxdomain.integration-testing.open-mpic.org', 'NXDOMAIN') + ]) + def api_should_return_200_is_valid_false_given_invalid_dns_01_validation(self, api_client, domain_or_ip_target, purpose_of_test): + print(f"Running test for {domain_or_ip_target} ({purpose_of_test})") + request = MpicDcvRequest( + domain_or_ip_target=domain_or_ip_target, + orchestration_parameters=MpicRequestOrchestrationParameters(perspective_count=3, quorum_count=2), + dcv_check_parameters=DcvCheckParameters( + validation_details=DcvAcmeDns01ValidationDetails(key_authorization="7FwkJPsKf-TH54wu4eiIFA3nhzYaevsL7953ihy-tpo") + ) + ) + + print("\nRequest:\n", json.dumps(request.model_dump(), indent=4)) # pretty print request body + response = api_client.post(MPIC_REQUEST_PATH, json.dumps(request.model_dump())) + assert response.status_code == 200 + mpic_response = self.mpic_response_adapter.validate_json(response.text) + + assert mpic_response.is_valid is False + + @pytest.mark.parametrize('domain_or_ip_target, dns_record_type, challenge_value, purpose_of_test', [ + ('dns-change-txt.integration-testing.open-mpic.org', DnsRecordType.TXT, "1234567890abcdefg.", 'standard TXT dns change'), + ('dns-change-cname.integration-testing.open-mpic.org', DnsRecordType.CNAME, "1234567890abcdefg.", 'standard CNAME dns change'), + ('dns-change-caa.integration-testing.open-mpic.org', DnsRecordType.CAA, '0 dnschange "1234567890abcdefg."', 'standard CAA dns change'), + ]) + def api_should_return_200_is_valid_true_given_valid_dns_change_validation(self, api_client, domain_or_ip_target, dns_record_type, challenge_value, purpose_of_test): + print(f"Running test for {domain_or_ip_target} ({purpose_of_test})") + request = MpicDcvRequest( + domain_or_ip_target=domain_or_ip_target, + orchestration_parameters=MpicRequestOrchestrationParameters(perspective_count=3, quorum_count=2), + dcv_check_parameters=DcvCheckParameters( + validation_details=DcvDnsChangeValidationDetails(challenge_value=challenge_value, dns_record_type=dns_record_type, dns_name_prefix="") + ) + ) + + print("\nRequest:\n", json.dumps(request.model_dump(), indent=4)) # pretty print request body + response = api_client.post(MPIC_REQUEST_PATH, json.dumps(request.model_dump())) + assert response.status_code == 200 + print("\nResponse:\n", json.dumps(json.loads(response.text), indent=4)) # pretty print request body + + mpic_response = self.mpic_response_adapter.validate_json(response.text) + + assert mpic_response.is_valid is True def api_should_return_200_and_failed_corroboration_given_failed_dcv_check(self, api_client): request = MpicDcvRequest(