Coverage for node / src / stigmem_node / models / auth.py: 100%

37 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-25 01:49 +0000

1"""Authentication route wire-format models.""" 

2 

3from __future__ import annotations 

4 

5from pydantic import BaseModel, Field 

6 

7STATIC_KEY_MIN_RAW_LENGTH = 32 # matches bootstrap's `openssl rand -hex 32` 

8 

9 

10class ExchangeRequest(BaseModel): 

11 id_token: str 

12 permissions: list[str] = Field(default=["read", "write"]) 

13 

14 

15class ExchangeResponse(BaseModel): 

16 api_key: str 

17 entity_uri: str 

18 permissions: list[str] 

19 expires_at: str 

20 

21 

22class KeyInfo(BaseModel): 

23 id: str 

24 entity_uri: str 

25 permissions: list[str] 

26 description: str | None 

27 created_at: str 

28 expires_at: str | None 

29 oidc_sub: str | None 

30 

31 

32class ExpiringKeyInfo(KeyInfo): 

33 tenant_id: str 

34 days_remaining: float 

35 

36 

37class RegisterKeyRequest(BaseModel): 

38 raw_key: str = Field( 

39 ..., 

40 min_length=STATIC_KEY_MIN_RAW_LENGTH, 

41 description=( 

42 "Caller-generated raw key material (e.g. `openssl rand -hex 32`). " 

43 "The node hashes it and never stores or echoes the raw value." 

44 ), 

45 ) 

46 entity_uri: str = Field(..., min_length=1) 

47 permissions: list[str] = Field(default_factory=lambda: ["read", "write"]) 

48 description: str | None = None 

49 expires_at: str | None = Field( 

50 default=None, 

51 description="ISO-8601 timestamp; omit for no expiry.", 

52 ) 

53 tenant_id: str | None = Field( 

54 default=None, 

55 description="Target tenant; defaults to the caller's tenant.", 

56 ) 

57 

58 

59class RegisterKeyResponse(BaseModel): 

60 id: str 

61 entity_uri: str 

62 permissions: list[str] 

63 description: str | None 

64 created_at: str 

65 expires_at: str | None 

66 tenant_id: str