Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The above sample must be run from the root directory of a deployed Open MPIC aws

The API is compliant with the [Open MPIC Specification](https://github.com/open-mpic/open-mpic-specification).

There is [documentation based on the API specification used in this version](https://open-mpic.org/documentation.html?commit=149f38323babe01f0865565ae8a9a4deb0de8ec0).
There is [documentation based on the API specification used in this version](https://open-mpic.org/documentation.html?commit=371feaaed467a23089ef9b867d50649c345238e9).

## Development
Code changes can easily be deployed by editing the .py files and then rezipping the project via `./zip-all.sh` and `./2-package.sh` in the `layer` directory. Then, running `tofu apply` run from the open-tofu directory will update only on the required resources and leave the others unchanged. If any `.tf.template` files are changed or `config.yaml` is edited, `hatch run ./configure.py` must be rerun followed by `tofu apply` in the open-tofu directory.
Expand Down
39 changes: 22 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@ classifiers = [
dependencies = [
#"open-mpic-core @ git+https://github.com/open-mpic/open-mpic-core-python.git@birgelee-version-bump",
"pyyaml==6.0.2",
"requests==2.32.4",
"requests==2.33.0",
"dnspython==2.7.0",
"pydantic==2.11.7",
"aiohttp==3.13.3",
"aiohttp==3.13.4",
"aws-lambda-powertools[parser]==3.15.1",
"open-mpic-core==6.3.0",
"open-mpic-core==6.4.0",
"aioboto3~=14.3.0",
Comment thread
sciros marked this conversation as resolved.
"black==25.1.0",
]

[project.optional-dependencies]
dev = [
"black==26.3.0"
]
test = [
"pytest==8.4.1",
"pytest-cov==6.2.1",
Expand All @@ -56,7 +58,7 @@ Source = "https://github.com/open-mpic/aws-lambda-python"
#virtual = ".hatch"

[tool.api]
spec_version = "3.8.0"
spec_version = "3.9.0"
spec_repository = "https://github.com/open-mpic/open-mpic-specification"
Comment thread
sciros marked this conversation as resolved.

[tool.hatch]
Expand All @@ -68,12 +70,24 @@ build.targets.wheel.packages = ["src/aws_lambda_mpic"]
skip-install = false
type="virtual"
path="venv"
features = [
"dev",
"test",
]
installer = "pip"

[tool.hatch.envs.default.env-vars]
PIP_INDEX_URL = "https://pypi.org/simple/"
#PIP_EXTRA_INDEX_URL = "https://test.pypi.org/simple/" # FIXME here temporarily to test open-mpic-core packaging
PIP_VERBOSE = "1"

[tool.hatch.envs.default.scripts]
pre-install = "python -m ensurepip"
unit = "pytest"
unit-html = "pytest --html=testreports/index.html" # generate html report (warning: uses an aging plugin, 11-2023)
integration = "pytest tests/integration"
coverage = "pytest --cov=src/aws_lambda_mpic --cov-report=term-missing --cov-report=html"

[tool.hatch.envs.lambda]
skip-install = true
python = "3.11"
Expand Down Expand Up @@ -112,24 +126,15 @@ deploy-no-dnssec = [
"apply-tf-no-dnssec"
]

[tool.hatch.envs.dev]
template = "default"

[tool.hatch.envs.test]
skip-install = false
features = [
"test",
]
installer = "pip"
template = "default"

#[tool.hatch.envs.test.env-vars]
#PIP_EXTRA_INDEX_URL = "https://test.pypi.org/simple/"

[tool.hatch.envs.test.scripts]
pre-install = "python -m ensurepip"
unit = "pytest"
unit-html = "pytest --html=testreports/index.html" # generate html report (warning: uses an aging plugin, 11-2023)
integration = "pytest tests/integration"
coverage = "pytest --cov=src/aws_lambda_mpic --cov-report=term-missing --cov-report=html"

[tool.hatch.envs.hatch-test]
default-args = ["tests/unit"]
randomize = true
Expand Down
2 changes: 1 addition & 1 deletion src/aws_lambda_mpic/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.7.0"
__version__ = "1.8.0"
Comment thread
sciros marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ async def call_remote_perspective(
Payload=check_request.model_dump_json(), # AWS Lambda functions expect a JSON string for payload
)
response_payload = await response["Payload"].read()
if 'FunctionError' in response:
if "FunctionError" in response:
raise LambdaExecutionException(f"Lambda execution error: {response_payload.decode('utf-8')}")
response_payload = json.loads(response_payload)
return self.check_response_adapter.validate_json(response_payload["body"])
Expand Down
12 changes: 5 additions & 7 deletions tests/integration/test_deployed_mpic_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import testing_api_client


MPIC_REQUEST_PATH = "/mpic"


Expand Down Expand Up @@ -61,8 +60,9 @@ def api_should_return_200_and_passed_corroboration_given_successful_caa_check(se
# assert response body has a list of perspectives with length 2, and each element has response code 200
perspectives_list: list[PerspectiveResponse] = mpic_response.perspectives
assert len(perspectives_list) == request.orchestration_parameters.perspective_count

assert (
len(list(filter(lambda perspective: perspective.check_response.check_type == CheckType.CAA, perspectives_list)))
len(list(filter(lambda p: p.check_response.check_type == CheckType.CAA, perspectives_list)))
== request.orchestration_parameters.perspective_count
)

Expand Down Expand Up @@ -109,9 +109,7 @@ def api_should_return_is_valid_false_for_all_tests_in_do_not_issue_caa_test_suit
mpic_response = self.mpic_response_adapter.validate_json(response.text)
assert mpic_response.is_valid is False

def api_should_return_is_valid_true_for_caa_lookup_failure_if_allow_lookup_failure_flag_is_true(
self, api_client
):
def api_should_return_is_valid_true_for_caa_lookup_failure_if_allow_lookup_failure_flag_is_true(self, api_client):
request = MpicCaaRequest(
domain_or_ip_target="servfail.caatestsuite-dnssec.com",
orchestration_parameters=MpicRequestOrchestrationParameters(perspective_count=3, quorum_count=2),
Expand Down Expand Up @@ -258,7 +256,7 @@ def api_should_return_200_given_valid_http_01_validation(
request = MpicDcvRequest(
domain_or_ip_target=domain_or_ip_target,
orchestration_parameters=MpicRequestOrchestrationParameters(perspective_count=3, quorum_count=2),
dcv_check_parameters=DcvAcmeHttp01ValidationParameters(key_authorization=key_authorization, token=token)
dcv_check_parameters=DcvAcmeHttp01ValidationParameters(key_authorization=key_authorization, token=token),
)
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()))
Expand Down Expand Up @@ -358,7 +356,7 @@ def api_should_return_200_is_valid_true_given_valid_dns_change_validation(
def api_should_return_200_and_failed_corroboration_given_failed_dcv_check(self, api_client):
request = MpicDcvRequest(
domain_or_ip_target="ifconfig.me",
dcv_check_parameters=DcvWebsiteChangeValidationParameters(http_token_path="/", challenge_value="test")
dcv_check_parameters=DcvWebsiteChangeValidationParameters(http_token_path="/", challenge_value="test"),
)

print("\nRequest:\n", json.dumps(request.model_dump(), indent=4)) # pretty print request body
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/aws_lambda_mpic/test_dcv_checker_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def lambda_handler__should_return_appropriate_status_code_given_errors_in_respon
):
mock_dcv_response = TestDcvCheckerLambda.create_dcv_check_response()
mock_dcv_response.check_passed = False
mock_dcv_response.errors = [(MpicValidationError(error_type=error_type, error_message=error_message))]
mock_dcv_response.errors = [MpicValidationError(error_type=error_type, error_message=error_message)]
mock_return_value = {
"statusCode": expected_status_code,
"headers": {"Content-Type": "application/json"},
Expand Down
31 changes: 20 additions & 11 deletions tests/unit/aws_lambda_mpic/test_mpic_coordinator_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
APIGatewayEventRequestContext,
APIGatewayEventIdentity,
)
from open_mpic_core.common_domain.enum.regional_internet_registry import RegionalInternetRegistry
from pydantic import TypeAdapter, BaseModel

from open_mpic_core import RemotePerspective
Expand Down Expand Up @@ -80,13 +81,17 @@ def set_env_variables():
def call_remote_perspective__should_make_aws_lambda_call_with_provided_arguments_and_return_check_response(
self, set_env_variables, mocker
):
lambda_handler, mock_client = self.mock_lambda_handler_for_lambda_invoke(mocker, self.create_successful_aioboto3_response_for_dcv_check)
lambda_handler, mock_client = self.mock_lambda_handler_for_lambda_invoke(
mocker, self.create_successful_aioboto3_response_for_dcv_check
)

dcv_check_request = ValidCheckCreator.create_valid_dns_check_request()
perspective_code = "us-west-1"
check_response = asyncio.get_event_loop().run_until_complete(lambda_handler.call_remote_perspective(
RemotePerspective(code=perspective_code, rir="arin"), CheckType.DCV, dcv_check_request
))
check_response = asyncio.get_event_loop().run_until_complete(
lambda_handler.call_remote_perspective(
RemotePerspective(code=perspective_code, rir="arin"), CheckType.DCV, dcv_check_request
)
)
assert check_response.check_passed is True
# hijacking the value of 'details.found_at' to verify that the right arguments got passed to the call
assert check_response.details.found_at == dcv_check_request.domain_or_ip_target
Expand All @@ -103,16 +108,20 @@ def call_remote_perspective__should_make_aws_lambda_call_with_provided_arguments
def call_remote_perspective__should_make_aws_lambda_call_and_handle_lambda_execution_exceptions(
self, set_env_variables, mocker
):
lambda_handler, mock_client = self.mock_lambda_handler_for_lambda_invoke(mocker, self.create_error_aioboto3_response)
lambda_handler, mock_client = self.mock_lambda_handler_for_lambda_invoke(
mocker, self.create_error_aioboto3_response
)

class Dummy(BaseModel):
pass

with pytest.raises(LambdaExecutionException) as exc_info:
asyncio.get_event_loop().run_until_complete(lambda_handler.call_remote_perspective(
RemotePerspective(code="us-west-1", rir="arin"), CheckType.DCV, Dummy()
))
assert exc_info.value.args[0] == "Lambda execution error: {\"errorMessage\": \"some message\"}"
asyncio.get_event_loop().run_until_complete(
lambda_handler.call_remote_perspective(
RemotePerspective(code="us-west-1", rir=RegionalInternetRegistry.ARIN), CheckType.DCV, Dummy()
)
)
assert exc_info.value.args[0] == 'Lambda execution error: {"errorMessage": "some message"}'

def lambda_handler__should_return_400_error_and_details_given_invalid_request_body(self):
request = ValidMpicRequestCreator.create_valid_dcv_mpic_request()
Expand Down Expand Up @@ -253,7 +262,7 @@ async def read(self):
return json_bytes

return {"Payload": MockStreamingBody()}

# noinspection PyUnusedLocal
async def create_error_aioboto3_response(self, *args, **kwargs):
expected_response = {"errorMessage": "some message"}
Expand All @@ -263,7 +272,7 @@ class MockStreamingBody:
# noinspection PyMethodMayBeStatic
async def read(self):
return json_bytes

# See https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda/client/invoke.html, "Response Structure"
return {"Payload": MockStreamingBody(), "FunctionError": None}

Expand Down
Loading