Coverage for src / lexigram / contracts / security / secrets.py: 0%

9 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-15 18:57 +0800

1"""Secret store protocol for Lexigram Framework. 

2 

3Provides a protocol for retrieving, storing, and deleting named secrets. 

4Implementations may delegate to environment variables, HashiCorp Vault, 

5AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, or a local 

6encrypted store, depending on the deployment environment. 

7 

8Example:: 

9 

10 from lexigram.contracts.secrets import SecretStoreProtocol 

11 

12 async def bootstrap(store: SecretStoreProtocol) -> None: 

13 api_key = await store.get_secret("stripe/api-key") 

14 db_url = await store.get_secret("database/url") 

15 

16Container registration:: 

17 

18 container.singleton(SecretStoreProtocol, EnvSecretStore) 

19""" 

20 

21from __future__ import annotations 

22 

23from typing import Protocol, runtime_checkable 

24 

25 

26@runtime_checkable 

27class SecretStoreProtocol(Protocol): 

28 """Protocol for retrieving, writing, and deleting named secrets. 

29 

30 Secret names may use any naming convention; a hierarchical path 

31 (e.g. ``"database/password"``) is recommended for readability and 

32 to align with most provider APIs. 

33 

34 All mutating operations (``set_secret``, ``delete_secret``) are 

35 **synchronous** at the protocol level — implementations may perform 

36 async I/O internally but the public contract accepts simple calls from 

37 both sync and async contexts. 

38 

39 Example:: 

40 

41 store = EnvSecretStore() 

42 val = store.get_secret("MY_API_KEY") 

43 

44 Async-first usage via a wrapping coroutine:: 

45 

46 val = await asyncio.to_thread(store.get_secret, "MY_API_KEY") 

47 """ 

48 

49 def get_secret(self, name: str) -> str: 

50 """Return the value of a secret by name. 

51 

52 Args: 

53 name: Unique secret identifier (e.g. ``"stripe/api-key"``). 

54 

55 Returns: 

56 The plaintext secret value. 

57 

58 Raises: 

59 SecretNotFoundError: If no secret with that name exists. 

60 SecretAccessError: If the caller lacks permission. 

61 """ 

62 ... 

63 

64 def set_secret(self, name: str, value: str) -> None: 

65 """Write or overwrite a secret. 

66 

67 Args: 

68 name: Unique secret identifier. 

69 value: Plaintext secret value to store. 

70 

71 Raises: 

72 SecretAccessError: If the caller lacks permission to write. 

73 """ 

74 ... 

75 

76 def delete_secret(self, name: str) -> None: 

77 """Delete a secret by name. 

78 

79 Non-existent secrets are silently ignored (idempotent delete). 

80 

81 Args: 

82 name: Unique secret identifier. 

83 

84 Raises: 

85 SecretAccessError: If the caller lacks permission to delete. 

86 """ 

87 ... 

88 

89 def has_secret(self, name: str) -> bool: 

90 """Return ``True`` if a secret with *name* exists, ``False`` otherwise. 

91 

92 Args: 

93 name: Unique secret identifier. 

94 """ 

95 ... 

96 

97 

98__all__ = [ 

99 "SecretStoreProtocol", 

100]