Repository: getmoto/moto

Issue:
Support Secrets Manager list-secrets
Implement support for `aws secretsmanager list-secrets`

Note: this API call is paginated.


Discussion:
#2102 may be related to this.

Resolving patch:
diff --git a/moto/secretsmanager/models.py b/moto/secretsmanager/models.py
--- a/moto/secretsmanager/models.py
+++ b/moto/secretsmanager/models.py
@@ -188,6 +188,31 @@ def get_random_password(self, password_length,
 
         return response
 
+    def list_secrets(self, max_results, next_token):
+        # TODO implement pagination and limits
+
+        secret_list = [{
+            "ARN": secret_arn(self.region, secret['secret_id']),
+            "DeletedDate": None,
+            "Description": "",
+            "KmsKeyId": "",
+            "LastAccessedDate": None,
+            "LastChangedDate": None,
+            "LastRotatedDate": None,
+            "Name": secret['name'],
+            "RotationEnabled": secret['rotation_enabled'],
+            "RotationLambdaARN": secret['rotation_lambda_arn'],
+            "RotationRules": {
+                "AutomaticallyAfterDays": secret['auto_rotate_after_days']
+            },
+            "SecretVersionsToStages": {
+                secret['version_id']: ["AWSCURRENT"]
+            },
+            "Tags": secret['tags']
+        } for secret in self.secrets.values()]
+
+        return secret_list, None
+
 
 available_regions = (
     boto3.session.Session().get_available_regions("secretsmanager")
diff --git a/moto/secretsmanager/responses.py b/moto/secretsmanager/responses.py
--- a/moto/secretsmanager/responses.py
+++ b/moto/secretsmanager/responses.py
@@ -4,6 +4,8 @@
 
 from .models import secretsmanager_backends
 
+import json
+
 
 class SecretsManagerResponse(BaseResponse):
 
@@ -64,3 +66,12 @@ def rotate_secret(self):
             rotation_lambda_arn=rotation_lambda_arn,
             rotation_rules=rotation_rules
         )
+
+    def list_secrets(self):
+        max_results = self._get_int_param("MaxResults")
+        next_token = self._get_param("NextToken")
+        secret_list, next_token = secretsmanager_backends[self.region].list_secrets(
+            max_results=max_results,
+            next_token=next_token,
+        )
+        return json.dumps(dict(SecretList=secret_list, NextToken=next_token))


Test patch:
diff --git a/tests/test_secretsmanager/test_secretsmanager.py b/tests/test_secretsmanager/test_secretsmanager.py
--- a/tests/test_secretsmanager/test_secretsmanager.py
+++ b/tests/test_secretsmanager/test_secretsmanager.py
@@ -203,6 +203,42 @@ def test_describe_secret_that_does_not_match():
     with assert_raises(ClientError):
         result = conn.get_secret_value(SecretId='i-dont-match')
 
+
+@mock_secretsmanager
+def test_list_secrets_empty():
+    conn = boto3.client('secretsmanager', region_name='us-west-2')
+
+    secrets = conn.list_secrets()
+
+    assert secrets['SecretList'] == []
+
+
+@mock_secretsmanager
+def test_list_secrets():
+    conn = boto3.client('secretsmanager', region_name='us-west-2')
+
+    conn.create_secret(Name='test-secret',
+                       SecretString='foosecret')
+
+    conn.create_secret(Name='test-secret-2',
+                       SecretString='barsecret',
+                       Tags=[{
+                           'Key': 'a',
+                           'Value': '1'
+                       }])
+
+    secrets = conn.list_secrets()
+
+    assert secrets['SecretList'][0]['ARN'] is not None
+    assert secrets['SecretList'][0]['Name'] == 'test-secret'
+    assert secrets['SecretList'][1]['ARN'] is not None
+    assert secrets['SecretList'][1]['Name'] == 'test-secret-2'
+    assert secrets['SecretList'][1]['Tags'] == [{
+        'Key': 'a',
+        'Value': '1'
+    }]
+
+
 @mock_secretsmanager
 def test_rotate_secret():
     secret_name = 'test-secret'