Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.
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 localstack-core/localstack/services/ses/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ def set_identity_headers_in_notifications_enabled(
)

backend = get_ses_backend(context)
if identity not in backend.addresses:
if identity not in backend.email_identities:
raise MessageRejected(f"Identity {identity} is not verified or does not exist.")

# Store the setting in the backend
Expand Down
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,7 @@ runtime = [
"json5>=0.9.11",
"jsonpath-ng>=1.6.1",
"jsonpath-rw>=1.4.0",
# TODO revert pin once moto upgrade is completed
# "moto-ext[all]>=5.1.12.post22",
"moto-ext[all]==5.1.14.post7",
"moto-ext[all]>=5.1.12.post22",
"opensearch-py>=2.4.1",
"pymongo>=4.2.0",
"pyopenssl>=23.0.0",
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ mdurl==0.1.2
# via markdown-it-py
more-itertools==10.8.0
# via openapi-core
moto-ext==5.1.14.post7
moto-ext==5.1.14.post34
# via localstack-core
mpmath==1.3.0
# via sympy
Expand Down
2 changes: 1 addition & 1 deletion requirements-runtime.txt
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ mdurl==0.1.2
# via markdown-it-py
more-itertools==10.8.0
# via openapi-core
moto-ext==5.1.14.post7
moto-ext==5.1.14.post34
# via localstack-core (pyproject.toml)
mpmath==1.3.0
# via sympy
Expand Down
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ mdurl==0.1.2
# via markdown-it-py
more-itertools==10.8.0
# via openapi-core
moto-ext==5.1.14.post7
moto-ext==5.1.14.post34
# via localstack-core
mpmath==1.3.0
# via sympy
Expand Down
2 changes: 1 addition & 1 deletion requirements-typehint.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ mdurl==0.1.2
# via markdown-it-py
more-itertools==10.8.0
# via openapi-core
moto-ext==5.1.14.post7
moto-ext==5.1.14.post34
# via localstack-core
mpmath==1.3.0
# via sympy
Expand Down
30 changes: 25 additions & 5 deletions tests/aws/services/acm/test_acm.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import pytest
from botocore.exceptions import ClientError
from localstack_snapshot.snapshots.transformer import SortingTransformer
from moto import settings as moto_settings

from localstack.testing.aws.util import is_aws_cloud
from localstack.testing.pytest import markers
from localstack.utils.crypto import generate_ssl_cert
from localstack.utils.strings import short_uid
from localstack.utils.sync import retry
from localstack.utils.sync import retry, wait_until


class TestACM:
Expand All @@ -27,7 +28,7 @@ class TestACM:
]
)
def test_import_certificate(self, tmp_path, aws_client, cleanups, snapshot):
with pytest.raises(Exception) as exc_info:
with pytest.raises(ClientError) as exc_info:
aws_client.acm.import_certificate(Certificate=b"CERT123", PrivateKey=b"KEY123")
assert exc_info.value.response["Error"]["Code"] == "ValidationException"

Expand Down Expand Up @@ -72,6 +73,15 @@ def test_domain_validation(self, acm_request_certificate, aws_client, snapshot):
snapshot.add_transformer(snapshot.transform.key_value("SignatureAlgorithm"))

certificate_arn = acm_request_certificate()["CertificateArn"]

# we are manually waiting for some fields to be returned, as they are missing soon after creating the cert
def _cert_has_required_fields() -> bool:
_resp = aws_client.acm.describe_certificate(CertificateArn=certificate_arn)
return "DomainName" in _resp["Certificate"]

if is_aws_cloud():
wait_until(_cert_has_required_fields, wait=2, max_retries=20)

result = aws_client.acm.describe_certificate(CertificateArn=certificate_arn)
snapshot.match("describe-certificate", result)

Expand All @@ -84,8 +94,17 @@ def test_boto_wait_for_certificate_validation(
waiter = aws_client.acm.get_waiter("certificate_validated")
waiter.wait(CertificateArn=certificate_arn, WaiterConfig={"Delay": 0.5, "MaxAttempts": 3})

@markers.aws.validated
@markers.snapshot.skip_snapshot_verify(paths=["$..Certificate.SignatureAlgorithm"])
@markers.aws.manual_setup_required
# this test requires manual input to our DNS provider
@markers.snapshot.skip_snapshot_verify(
paths=[
"$..Certificate.SignatureAlgorithm",
# those should also be returned by AWS, but regenerating the snapshots needs manual input
# skipped for now, validated by other tests
"$..Certificate.Options.Export",
"$..Exported",
]
)
def test_certificate_for_subdomain_wildcard(
self, acm_request_certificate, aws_client, snapshot, monkeypatch
):
Expand Down Expand Up @@ -123,7 +142,7 @@ def _get_cert_with_records():
if is_aws_cloud():
# Wait until DNS entry has been added (needs to be done manually!)
# Note: When running parity tests against AWS, we need to add the CNAME record to our DNS
# server (currently with gandi.net), to enable validation of the certificate.
# server (currently with Route53), to enable validation of the certificate.
prompt = (
f"Please add the following CNAME entry to the LocalStack DNS server, then hit [ENTER] once "
f"the certificate has been validated in AWS: {dns_options['Name']} = {dns_options['Value']}"
Expand Down Expand Up @@ -161,6 +180,7 @@ def _get_cert_issued():
"$..ResourceRecord",
"$..SignatureAlgorithm",
"$..Serial",
"$..ExportOption",
]
)
def test_create_certificate_for_multiple_alternative_domains(
Expand Down
19 changes: 12 additions & 7 deletions tests/aws/services/acm/test_acm.snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,21 @@
}
},
"tests/aws/services/acm/test_acm.py::TestACM::test_create_certificate_for_multiple_alternative_domains": {
"recorded-date": "09-01-2024, 14:58:14",
"recorded-date": "14-10-2025, 09:18:38",
"recorded-content": {
"list-cert-summary-list": {
"CertificateArn": "arn:<partition>:acm:<region>:111111111111:certificate/<cert-id>",
"CreatedAt": "datetime",
"DomainName": "test.example.com",
"ExportOption": "DISABLED",
"Exported": false,
"ExtendedKeyUsages": [],
"HasAdditionalSubjectAlternativeNames": false,
"InUse": false,
"KeyAlgorithm": "RSA-2048",
"KeyUsages": [],
"RenewalEligibility": "INELIGIBLE",
"Status": "FAILED",
"Status": "PENDING_VALIDATION",
"SubjectAlternativeNameSummaries": [
"*.test.example.com",
"another.domain.com",
Expand Down Expand Up @@ -201,7 +203,8 @@
"KeyAlgorithm": "RSA-2048",
"KeyUsages": [],
"Options": {
"CertificateTransparencyLoggingPreference": "ENABLED"
"CertificateTransparencyLoggingPreference": "ENABLED",
"Export": "DISABLED"
},
"RenewalEligibility": "INELIGIBLE",
"SignatureAlgorithm": "SHA256WITHRSA",
Expand All @@ -218,7 +221,7 @@
}
},
"tests/aws/services/acm/test_acm.py::TestACM::test_import_certificate": {
"recorded-date": "22-02-2024, 17:41:15",
"recorded-date": "14-10-2025, 09:17:56",
"recorded-content": {
"import-certificate-response": {
"CertificateArn": "arn:<partition>:acm:<region>:111111111111:certificate/<cert-id>",
Expand Down Expand Up @@ -270,7 +273,8 @@
"NotAfter": "datetime",
"NotBefore": "datetime",
"Options": {
"CertificateTransparencyLoggingPreference": "DISABLED"
"CertificateTransparencyLoggingPreference": "DISABLED",
"Export": "DISABLED"
},
"RenewalEligibility": "INELIGIBLE",
"Serial": "03:e9",
Expand All @@ -293,7 +297,7 @@
}
},
"tests/aws/services/acm/test_acm.py::TestACM::test_domain_validation": {
"recorded-date": "12-04-2024, 15:36:37",
"recorded-date": "14-10-2025, 09:31:48",
"recorded-content": {
"describe-certificate": {
"Certificate": {
Expand All @@ -315,7 +319,8 @@
"KeyAlgorithm": "RSA-2048",
"KeyUsages": [],
"Options": {
"CertificateTransparencyLoggingPreference": "ENABLED"
"CertificateTransparencyLoggingPreference": "ENABLED",
"Export": "DISABLED"
},
"RenewalEligibility": "INELIGIBLE",
"SignatureAlgorithm": "<signature-algorithm:1>",
Expand Down
24 changes: 21 additions & 3 deletions tests/aws/services/acm/test_acm.validation.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,30 @@
"last_validated_date": "2023-04-18T17:01:27+00:00"
},
"tests/aws/services/acm/test_acm.py::TestACM::test_create_certificate_for_multiple_alternative_domains": {
"last_validated_date": "2024-01-09T14:58:14+00:00"
"last_validated_date": "2025-10-14T09:18:39+00:00",
"durations_in_seconds": {
"setup": 0.45,
"call": 5.97,
"teardown": 0.19,
"total": 6.61
}
},
"tests/aws/services/acm/test_acm.py::TestACM::test_domain_validation": {
"last_validated_date": "2024-04-12T15:36:37+00:00"
"last_validated_date": "2025-10-14T09:31:48+00:00",
"durations_in_seconds": {
"setup": 0.46,
"call": 2.94,
"teardown": 0.21,
"total": 3.61
}
},
"tests/aws/services/acm/test_acm.py::TestACM::test_import_certificate": {
"last_validated_date": "2024-02-22T17:41:15+00:00"
"last_validated_date": "2025-10-14T09:17:56+00:00",
"durations_in_seconds": {
"setup": 0.48,
"call": 1.25,
"teardown": 0.25,
"total": 1.98
}
}
}
Loading