1+ from typing import Dict , List , Optional
2+
13from fastapi import APIRouter , Depends , Query
4+ from fastapi .responses import JSONResponse
5+ from pydantic import BaseModel
26
37from feast .api .registry .rest .rest_utils import (
48 create_grpc_pagination_params ,
913 get_sorting_params ,
1014 grpc_call ,
1115)
12- from feast .registry_server import RegistryServer_pb2
16+ from feast .protos .feast .core .Permission_pb2 import Permission as PermissionProto
17+ from feast .protos .feast .core .Permission_pb2 import PermissionSpec as PermissionSpecProto
18+ from feast .protos .feast .core .Policy_pb2 import (
19+ CombinedGroupNamespacePolicy as CombinedGroupNamespacePolicyProto ,
20+ )
21+ from feast .protos .feast .core .Policy_pb2 import GroupBasedPolicy as GroupBasedPolicyProto
22+ from feast .protos .feast .core .Policy_pb2 import (
23+ NamespaceBasedPolicy as NamespaceBasedPolicyProto ,
24+ )
25+ from feast .protos .feast .core .Policy_pb2 import Policy as PolicyProto
26+ from feast .protos .feast .core .Policy_pb2 import RoleBasedPolicy as RoleBasedPolicyProto
27+ from feast .protos .feast .registry import RegistryServer_pb2
28+
29+
30+ class RoleBasedPolicyModel (BaseModel ):
31+ roles : List [str ]
32+
33+
34+ class GroupBasedPolicyModel (BaseModel ):
35+ groups : List [str ]
36+
37+
38+ class NamespaceBasedPolicyModel (BaseModel ):
39+ namespaces : List [str ]
40+
41+
42+ class CombinedGroupNamespacePolicyModel (BaseModel ):
43+ groups : List [str ]
44+ namespaces : List [str ]
45+
46+
47+ class PolicyModel (BaseModel ):
48+ role_based_policy : Optional [RoleBasedPolicyModel ] = None
49+ group_based_policy : Optional [GroupBasedPolicyModel ] = None
50+ namespace_based_policy : Optional [NamespaceBasedPolicyModel ] = None
51+ combined_group_namespace_policy : Optional [CombinedGroupNamespacePolicyModel ] = None
52+
53+
54+ class ApplyPermissionRequestBody (BaseModel ):
55+ name : str
56+ project : str
57+ types : List [str ] = []
58+ name_patterns : List [str ] = []
59+ actions : List [str ] = []
60+ policy : PolicyModel
61+ tags : Optional [Dict [str , str ]] = {}
62+ required_tags : Optional [Dict [str , str ]] = {}
63+
64+
65+ def _build_policy_proto (policy : PolicyModel ) -> PolicyProto :
66+ if policy .role_based_policy :
67+ return PolicyProto (
68+ role_based_policy = RoleBasedPolicyProto (roles = policy .role_based_policy .roles )
69+ )
70+ elif policy .group_based_policy :
71+ return PolicyProto (
72+ group_based_policy = GroupBasedPolicyProto (
73+ groups = policy .group_based_policy .groups
74+ )
75+ )
76+ elif policy .namespace_based_policy :
77+ return PolicyProto (
78+ namespace_based_policy = NamespaceBasedPolicyProto (
79+ namespaces = policy .namespace_based_policy .namespaces
80+ )
81+ )
82+ elif policy .combined_group_namespace_policy :
83+ return PolicyProto (
84+ combined_group_namespace_policy = CombinedGroupNamespacePolicyProto (
85+ groups = policy .combined_group_namespace_policy .groups ,
86+ namespaces = policy .combined_group_namespace_policy .namespaces ,
87+ )
88+ )
89+ return PolicyProto ()
90+
91+
92+ _TYPE_NAME_TO_ENUM = {
93+ "FEATURE_VIEW" : PermissionSpecProto .Type .FEATURE_VIEW ,
94+ "ON_DEMAND_FEATURE_VIEW" : PermissionSpecProto .Type .ON_DEMAND_FEATURE_VIEW ,
95+ "BATCH_FEATURE_VIEW" : PermissionSpecProto .Type .BATCH_FEATURE_VIEW ,
96+ "STREAM_FEATURE_VIEW" : PermissionSpecProto .Type .STREAM_FEATURE_VIEW ,
97+ "ENTITY" : PermissionSpecProto .Type .ENTITY ,
98+ "FEATURE_SERVICE" : PermissionSpecProto .Type .FEATURE_SERVICE ,
99+ "DATA_SOURCE" : PermissionSpecProto .Type .DATA_SOURCE ,
100+ "VALIDATION_REFERENCE" : PermissionSpecProto .Type .VALIDATION_REFERENCE ,
101+ "SAVED_DATASET" : PermissionSpecProto .Type .SAVED_DATASET ,
102+ "PERMISSION" : PermissionSpecProto .Type .PERMISSION ,
103+ "PROJECT" : PermissionSpecProto .Type .PROJECT ,
104+ "LABEL_VIEW" : PermissionSpecProto .Type .LABEL_VIEW ,
105+ }
106+
107+ _ACTION_NAME_TO_ENUM = {
108+ "CREATE" : PermissionSpecProto .AuthzedAction .CREATE ,
109+ "DESCRIBE" : PermissionSpecProto .AuthzedAction .DESCRIBE ,
110+ "UPDATE" : PermissionSpecProto .AuthzedAction .UPDATE ,
111+ "DELETE" : PermissionSpecProto .AuthzedAction .DELETE ,
112+ "READ_ONLINE" : PermissionSpecProto .AuthzedAction .READ_ONLINE ,
113+ "READ_OFFLINE" : PermissionSpecProto .AuthzedAction .READ_OFFLINE ,
114+ "WRITE_ONLINE" : PermissionSpecProto .AuthzedAction .WRITE_ONLINE ,
115+ "WRITE_OFFLINE" : PermissionSpecProto .AuthzedAction .WRITE_OFFLINE ,
116+ }
13117
14118
15119def get_permission_router (grpc_handler ) -> APIRouter :
@@ -33,8 +137,6 @@ def get_permission(
33137
34138 result = permission
35139
36- # Note: permissions may not have relationships in the traditional sense
37- # but we include the functionality for consistency
38140 if include_relationships :
39141 relationships = get_object_relationships (
40142 grpc_handler , "permission" , name , project , allow_cache
@@ -75,4 +177,53 @@ def list_permissions(
75177
76178 return result
77179
180+ @router .post ("/permissions" , status_code = 201 )
181+ def apply_permission (body : ApplyPermissionRequestBody ):
182+ types = [_TYPE_NAME_TO_ENUM [t ] for t in body .types if t in _TYPE_NAME_TO_ENUM ]
183+ actions = [
184+ _ACTION_NAME_TO_ENUM [a ] for a in body .actions if a in _ACTION_NAME_TO_ENUM
185+ ]
186+ policy_proto = _build_policy_proto (body .policy )
187+
188+ permission_spec = PermissionSpecProto (
189+ name = body .name ,
190+ types = types ,
191+ name_patterns = body .name_patterns ,
192+ actions = actions ,
193+ policy = policy_proto ,
194+ tags = body .tags or {},
195+ required_tags = body .required_tags or {},
196+ )
197+ permission_proto = PermissionProto (spec = permission_spec )
198+
199+ req = RegistryServer_pb2 .ApplyPermissionRequest (
200+ permission = permission_proto ,
201+ project = body .project ,
202+ commit = True ,
203+ )
204+ grpc_call (grpc_handler .ApplyPermission , req )
205+
206+ return JSONResponse (
207+ status_code = 201 ,
208+ content = {
209+ "name" : body .name ,
210+ "project" : body .project ,
211+ "status" : "applied" ,
212+ },
213+ )
214+
215+ @router .delete ("/permissions/{name}" )
216+ def delete_permission (
217+ name : str ,
218+ project : str = Query (...),
219+ ):
220+ req = RegistryServer_pb2 .DeletePermissionRequest (
221+ name = name ,
222+ project = project ,
223+ commit = True ,
224+ )
225+ grpc_call (grpc_handler .DeletePermission , req )
226+
227+ return {"name" : name , "project" : project , "status" : "deleted" }
228+
78229 return router
0 commit comments