1010from playbooks .utils .decorators import web_api
1111from playbooks .utils .meta import get_meta
1212from playbooks .utils .queryset import filter_page
13- from protos .base_pb2 import Message
13+ from protos .base_pb2 import Message , Meta , Page
1414from protos .secrets .api_pb2 import (
1515 GetSecretsRequest , GetSecretsResponse ,
1616 GetSecretRequest , GetSecretResponse ,
1717 CreateSecretRequest , CreateSecretResponse ,
1818 UpdateSecretRequest , UpdateSecretResponse ,
1919 Secret as SecretProto ,
20- UpdateSecretOp
2120)
2221
2322logger = logging .getLogger (__name__ )
@@ -37,27 +36,60 @@ def _secret_to_proto(secret: Secret) -> SecretProto:
3736 key = StringValue (value = secret .key ),
3837 masked_value = StringValue (value = _mask_secret_value (secret .value )),
3938 description = StringValue (value = secret .description or "" ),
40- creator = StringValue (value = secret .creator .email if secret .creator else "" ),
39+ created_by = StringValue (value = secret .created_by .email if secret .created_by else "" ),
4140 last_updated_by = StringValue (value = secret .last_updated_by .email if secret .last_updated_by else "" ),
4241 created_at = int (secret .created_at .replace (tzinfo = timezone .utc ).timestamp ()) if secret .created_at else 0 ,
4342 updated_at = int (secret .updated_at .replace (tzinfo = timezone .utc ).timestamp ()) if secret .updated_at else 0 ,
4443 is_active = secret .is_active
4544 )
4645
46+ def _secret_to_proto_partial (secret : Secret ) -> SecretProto :
47+ """Convert a Secret model to a partial Secret proto (for list views)"""
48+ return SecretProto (
49+ id = StringValue (value = str (secret .id )),
50+ key = StringValue (value = secret .key ),
51+ description = StringValue (value = secret .description or "" ),
52+ created_by = StringValue (value = secret .created_by .email if secret .created_by else "" ),
53+ created_at = int (secret .created_at .replace (tzinfo = timezone .utc ).timestamp ()) if secret .created_at else 0 ,
54+ is_active = secret .is_active
55+ )
56+
57+
4758
4859@web_api (GetSecretsRequest )
4960def secrets_list (request_message : GetSecretsRequest ) -> Union [GetSecretsResponse , HttpResponse ]:
50- """List all active secrets for the current account """
61+ """List secrets with optional filtering by IDs or key """
5162 account : Account = get_request_account ()
52-
53- # Get all active secrets for this account
63+ meta : Meta = request_message .meta
64+ show_inactive = meta .show_inactive
65+ page : Page = meta .page
66+ list_all = True
67+
68+ # Base queryset
5469 qs = Secret .objects .filter (account = account , is_active = True )
55-
56- # Apply pagination
70+
71+ # Filter by specific IDs if provided
72+ if request_message .secret_ids :
73+ qs = qs .filter (id__in = request_message .secret_ids )
74+ list_all = False
75+ # Filter by key if provided
76+ if request_message .key :
77+ qs = qs .filter (key__icontains = request_message .key .value .lower ())
78+ list_all = False
79+ # Otherwise filter by active status unless show_inactive is True
80+ elif not show_inactive or not show_inactive .value :
81+ qs = qs .filter (is_active = True )
82+
5783 total_count = qs .count ()
58- page = request_message .meta .page
59- secrets = [_secret_to_proto (secret ) for secret in filter_page (qs .order_by ("-created_at" ), page )]
60-
84+ qs = qs .order_by ('-created_at' )
85+ qs = filter_page (qs , page )
86+
87+ # Use proto or proto_partial based on list_all flag
88+ if list_all :
89+ secrets = [_secret_to_proto_partial (secret ) for secret in qs ]
90+ else :
91+ secrets = [_secret_to_proto (secret ) for secret in qs ]
92+
6193 return GetSecretsResponse (
6294 meta = get_meta (page = page , total_count = total_count ),
6395 success = BoolValue (value = True ),
@@ -108,7 +140,16 @@ def secret_create(request_message: CreateSecretRequest) -> Union[CreateSecretRes
108140 return CreateSecretResponse (
109141 meta = get_meta (),
110142 success = BoolValue (value = False ),
111- message = Message (title = "Invalid Request" , description = "Key, and value are required" )
143+ message = Message (title = "Invalid Request" , description = "Key and value are required" )
144+ )
145+
146+ # Validate key format -> (single word, no spaces, only alphanumeric and underscores)
147+ if not key .isalnum () or ' ' in key :
148+ return CreateSecretResponse (
149+ meta = get_meta (),
150+ success = BoolValue (value = False ),
151+ message = Message (title = "Invalid Key" ,
152+ description = "Key must be a single word containing only letters, numbers, and underscores" )
112153 )
113154
114155 # Check if key already exists for this account
@@ -126,7 +167,7 @@ def secret_create(request_message: CreateSecretRequest) -> Union[CreateSecretRes
126167 key = key ,
127168 value = value ,
128169 description = description ,
129- creator = user ,
170+ created_by = user ,
130171 last_updated_by = user ,
131172 is_active = True
132173 )
@@ -219,4 +260,4 @@ def secret_update(request_message: UpdateSecretRequest) -> Union[UpdateSecretRes
219260 meta = get_meta (),
220261 success = BoolValue (value = False ),
221262 message = Message (title = "Error" , description = "Failed to update secret" )
222- )
263+ )
0 commit comments