From c75307e61be50ad34bb200091205e627825289f9 Mon Sep 17 00:00:00 2001 From: Benjamin Simon Date: Tue, 5 Sep 2023 22:56:57 +0200 Subject: [PATCH 1/2] fix secretsmanager PutSecretValue on empty secret --- .../services/secretsmanager/provider.py | 20 +++++++++-- .../secretsmanager/test_secretsmanager.py | 24 +++++++++++++ .../test_secretsmanager.snapshot.json | 35 +++++++++++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/localstack/services/secretsmanager/provider.py b/localstack/services/secretsmanager/provider.py index e3fd9d07a9e91..6b69ce90e47a5 100644 --- a/localstack/services/secretsmanager/provider.py +++ b/localstack/services/secretsmanager/provider.py @@ -445,8 +445,8 @@ def backend_update_secret( return json.dumps(resp) -@patch(SecretsManagerResponse.update_secret) -def response_update_secret(_, self): +@patch(SecretsManagerResponse.update_secret, pass_target=False) +def response_update_secret(self): secret_id = self._get_param("SecretId") description = self._get_param("Description") secret_string = self._get_param("SecretString") @@ -495,7 +495,21 @@ def backend_update_secret_version_stage( @patch(FakeSecret.reset_default_version) def fake_secret_reset_default_version(fn, self, secret_version, version_id): - fn(self, secret_version, version_id) + # fn(self, secret_version, version_id) + + # remove all old AWSPREVIOUS stages + for old_version in self.versions.values(): + if "AWSPREVIOUS" in old_version["version_stages"]: + old_version["version_stages"].remove("AWSPREVIOUS") + + # set old AWSCURRENT secret to AWSPREVIOUS + if self.default_version_id in self.versions: + previous_current_version_id = self.default_version_id + self.versions[previous_current_version_id]["version_stages"] = ["AWSPREVIOUS"] # type: ignore + + self.versions[version_id] = secret_version + self.default_version_id = version_id + # Remove versions with no version stages. versions_no_stages = [ version_id for version_id, version in self.versions.items() if not version["version_stages"] diff --git a/tests/aws/services/secretsmanager/test_secretsmanager.py b/tests/aws/services/secretsmanager/test_secretsmanager.py index 74a1a37a2cdea..913a1ee6774aa 100644 --- a/tests/aws/services/secretsmanager/test_secretsmanager.py +++ b/tests/aws/services/secretsmanager/test_secretsmanager.py @@ -1973,3 +1973,27 @@ def test_no_client_request_token( exc_response = {"Error": response.json(), "Metadata": {"StatusCode": response.status_code}} sm_snapshot.match("no-client-request-exc", exc_response) + + @markers.aws.validated + def test_create_secret_version_from_empty_secret(self, aws_client, snapshot, cleanups): + snapshot.add_transformer(snapshot.transform.resource_name("secret-version"), priority=-1) + snapshot.add_transformer(snapshot.transform.key_value("Name")) + + response = aws_client.secretsmanager.create_secret( + Name=f"test-version-{short_uid()}", Description="" + ) + snapshot.match("create-empty-secret", response) + secret_id = response["ARN"] + cleanups.append( + lambda: aws_client.secretsmanager.delete_secret( + SecretId=secret_id, ForceDeleteWithoutRecovery=True + ) + ) + + response = aws_client.secretsmanager.describe_secret(SecretId=secret_id) + snapshot.match("describe-secret", response) + + response = aws_client.secretsmanager.put_secret_value( + SecretId=secret_id, SecretString="example-string-to-protect" + ) + snapshot.match("put-secret-value", response) diff --git a/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json b/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json index 1d347cbddb3e0..7336b9e252034 100644 --- a/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json +++ b/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json @@ -3650,5 +3650,40 @@ } } } + }, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_secret_version_from_empty_secret": { + "recorded-date": "05-09-2023, 22:19:06", + "recorded-content": { + "create-empty-secret": { + "ARN": "arn:aws:secretsmanager::111111111111:secret:", + "Name": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-secret": { + "ARN": "arn:aws:secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "LastChangedDate": "datetime", + "Name": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-secret-value": { + "ARN": "arn:aws:secretsmanager::111111111111:secret:", + "Name": "", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } From 9904e21a8021c83c4f2bcb423d1afddb578c62dd Mon Sep 17 00:00:00 2001 From: Benjamin Simon Date: Tue, 5 Sep 2023 23:00:56 +0200 Subject: [PATCH 2/2] add removal comment --- localstack/services/secretsmanager/provider.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/localstack/services/secretsmanager/provider.py b/localstack/services/secretsmanager/provider.py index 6b69ce90e47a5..79f70164f9537 100644 --- a/localstack/services/secretsmanager/provider.py +++ b/localstack/services/secretsmanager/provider.py @@ -496,7 +496,7 @@ def backend_update_secret_version_stage( @patch(FakeSecret.reset_default_version) def fake_secret_reset_default_version(fn, self, secret_version, version_id): # fn(self, secret_version, version_id) - + # FIXME: remove for the next moto bump (above 4.2.post1) and uncomment line above # remove all old AWSPREVIOUS stages for old_version in self.versions.values(): if "AWSPREVIOUS" in old_version["version_stages"]: @@ -509,6 +509,7 @@ def fake_secret_reset_default_version(fn, self, secret_version, version_id): self.versions[version_id] = secret_version self.default_version_id = version_id + # Remove until here ^ # Remove versions with no version stages. versions_no_stages = [