diff --git a/moto/secretsmanager/list_secrets/filters.py b/moto/secretsmanager/list_secrets/filters.py index 659d4c636ce3..233550175499 100644 --- a/moto/secretsmanager/list_secrets/filters.py +++ b/moto/secretsmanager/list_secrets/filters.py @@ -9,7 +9,7 @@ def name_filter(secret: "FakeSecret", names: List[str]) -> bool: def description_filter(secret: "FakeSecret", descriptions: List[str]) -> bool: - return _matcher(descriptions, [secret.description]) # type: ignore + return _matcher(descriptions, [secret.description], match_prefix=False) # type: ignore def tag_key(secret: "FakeSecret", tag_keys: List[str]) -> bool: @@ -30,21 +30,31 @@ def filter_all(secret: "FakeSecret", values: List[str]) -> bool: return _matcher(values, attributes) # type: ignore -def _matcher(patterns: List[str], strings: List[str]) -> bool: +def _matcher( + patterns: List[str], strings: List[str], match_prefix: bool = True +) -> bool: for pattern in [p for p in patterns if p.startswith("!")]: for string in strings: - if _match_pattern(pattern[1:], string): - return False + if not _match_pattern(pattern[1:], string, match_prefix): + return True for pattern in [p for p in patterns if not p.startswith("!")]: for string in strings: - if _match_pattern(pattern, string): + if _match_pattern(pattern, string, match_prefix): return True return False -def _match_pattern(pattern: str, value: str) -> bool: - for word in pattern.split(" "): - if word not in value: - return False +def _match_pattern(pattern: str, value: str, match_prefix: bool = True) -> bool: + if match_prefix: + return value.startswith(pattern) + else: + pattern_words = pattern.split(" ") + value_words = value.split(" ") + for pattern_word in pattern_words: + # all words in value must start with pattern_word + if not any( + value_word.startswith(pattern_word) for value_word in value_words + ): + return False return True diff --git a/tests/test_secretsmanager/test_list_secrets.py b/tests/test_secretsmanager/test_list_secrets.py index 32dadb7dc044..1acb8a9d3bdf 100644 --- a/tests/test_secretsmanager/test_list_secrets.py +++ b/tests/test_secretsmanager/test_list_secrets.py @@ -268,7 +268,13 @@ def test_with_filter_with_negation(): ) secret_names = list(map(lambda s: s["Name"], secrets["SecretList"])) - assert secret_names == ["baz"] + for secret_name in ["foo", "bar", "baz"]: + assert secret_name in secret_names + + secrets = conn.list_secrets(Filters=[{"Key": "description", "Values": ["!o"]}]) + secret_names = list(map(lambda s: s["Name"], secrets["SecretList"])) + for secret_name in ["qux", "none"]: + assert secret_name in secret_names @mock_aws