diff --git a/authorization/model.fga.yaml b/authorization/model.fga.yaml new file mode 100644 index 00000000..55b7d1b6 --- /dev/null +++ b/authorization/model.fga.yaml @@ -0,0 +1,309 @@ +# SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Greenhouse contributors +# SPDX-License-Identifier: Apache-2.0 + +name: Heureka5 +model: |+ + model + schema 1.1 + + type user + + # New role type for grouping users + type role + relations + define admin: [user] + define component_scanner: [user] + define issue_scanner: [user] + + type support_group + relations + # Operations + define can_write: admin from role + define can_view: member or admin from role or component_scanner from role or issue_scanner from role + + # Roles + define member: [user, support_group#member] or member from support_group + + # Relations + define role: [role] + define support_group: [support_group] + + type service + relations + # Operations + define can_view: [user] or member or owner or admin from role or component_scanner from role or issue_scanner from role + define can_write: [user] or owner or admin from role + + # Roles + define member: [user] or member from support_group + define owner: [user] + + # Relations + define role: [role] + define support_group: [support_group] + + type component_instance + relations + #Operations + define can_view: [user] or owner_from_related_service or member_from_related_service or admin from role or component_scanner from role or issue_scanner from role + define can_write: [user] or admin from role or component_scanner from role + + #Roles + define member_from_related_service: member from related_service + define owner_from_related_service: owner from related_service + + # Relations + define related_service: [service] + define role: [role] + + type component_version + relations + # Operations + define can_view: [user] or owner_from_related_service or member_from_related_service or admin from role or component_scanner from role or issue_scanner from role + define can_write: [user] or admin from role or component_scanner from role or issue_scanner from role + + # Roles + define member_from_related_service: member_from_related_service from component_instance + define owner_from_related_service: owner_from_related_service from component_instance + + # Relations + define component_instance: [component_instance] + define role: [role] + + type issue_match + relations + define can_view: [user] or owner_from_related_service or member_from_related_service or admin from role or component_scanner from role or issue_scanner from role + define can_write: [user] or admin from role + + define member_from_related_service: member_from_related_service from component_instance + define owner_from_related_service: owner_from_related_service from component_instance + + # Relations + define component_instance: [component_instance] + define role: [role] + + type component + relations + # Operations + define can_view: [user] or admin from role or component_scanner from role or issue_scanner from role or owner_from_related_service or member_from_related_service + define can_write: [user] or admin from role or owner_from_related_service + + # Relations + define member_from_related_service: member_from_related_service from component_version + define owner_from_related_service: owner_from_related_service from component_version + + # Relations + define component_version: [component_version] + define role: [role] + +tuples: + # Define the roles + - user: user:system + relation: admin + object: role:system_role + + - user: user:k8s_asset_scanner + relation: component_scanner + object: role:system_role + + - user: user:keppel_scanner + relation: issue_scanner + object: role:system_role + + # Assign system role to each entity + # Support Groups + - user: role:system_role + relation: role + object: support_group:team_alpha + + - user: role:system_role + relation: role + object: support_group:team_beta + + # Services + - user: role:system_role + relation: role + object: service:service_1 + + - user: role:system_role + relation: role + object: service:service_2 + + # Component Instances + - user: role:system_role + relation: role + object: component_instance:comp_1 + + - user: role:system_role + relation: role + object: component_instance:comp_2 + + # Component Versions + - user: role:system_role + relation: role + object: component_version:version_1 + + - user: role:system_role + relation: role + object: component_version:version_2 + + # Components (assuming you have instances) + - user: role:system_role + relation: role + object: component:comp_1 + + # Issue Matches (assuming you have instances) + - user: role:system_role + relation: role + object: issue_match:match_1 + + # Service relations + - user: service:service_1 + relation: related_service + object: component_instance:comp_1 + + - user: component_instance:comp_1 + relation: component_instance + object: component_version:version_1 + + - user: service:service_2 + relation: related_service + object: component_instance:comp_2 + + - user: component_instance:comp_2 + relation: component_instance + object: component_version:version_2 + + - user: component_version:version_1 + relation: component_version + object: component:comp_1 + + - user: component_version:version_2 + relation: component_version + object: component:comp_2 + + + # Regular user permissions - copied from original + # Associate support groups with services + - user: support_group:team_alpha + relation: support_group + object: service:service_1 + + - user: support_group:team_beta + relation: support_group + object: service:service_2 + + # Assign members to support groups + - user: user:bob + relation: member + object: support_group:team_alpha + + - user: user:alice + relation: member + object: support_group:team_alpha + + - user: user:charlie + relation: member + object: support_group:team_beta + + - user: user:bob + relation: member + object: support_group:team_beta + + +tests: + - name: "System user access tests" + check: + - user: "user:system" + object: "support_group:team_alpha" + assertions: + can_view: true + can_write: true + - name: "Team Access Tests" + check: + - user: "user:bob" + object: "support_group:team_alpha" + assertions: + can_view: true + - user: "user:alice" + object: "support_group:team_alpha" + assertions: + can_view: true + - user: "user:charlie" + object: "support_group:team_alpha" + assertions: + can_view: false + - user: "user:charlie" + object: "support_group:team_beta" + assertions: + can_view: true + + - name: "Service Access Tests" + check: + - user: "user:bob" + object: "service:service_1" + assertions: + can_view: true + can_write: false + - user: "user:alice" + object: "service:service_1" + assertions: + can_view: true + can_write: false + - user: "user:charlie" + object: "service:service_1" + assertions: + can_view: false + - user: "user:system" + object: "service:service_1" + assertions: + can_view: true + can_write: true + - user: "user:k8s_asset_scanner" + object: "service:service_1" + assertions: + can_view: true + can_write: false + - name: "Component Version Access Tests" + check: + - user: "user:bob" + object: "component_version:version_1" + assertions: + can_view: true + - user: "user:alice" + object: "component_version:version_1" + assertions: + can_view: true + - user: "user:charlie" + object: "component_version:version_1" + assertions: + can_view: false + - name: "Component Instance Access Tests" + check: + - user: "user:bob" + object: "component_instance:comp_1" + assertions: + can_view: true + can_write: false + - user: "user:alice" + object: "component_instance:comp_1" + assertions: + can_view: true + - user: "user:charlie" + object: "component_instance:comp_1" + assertions: + can_view: false + - user: "user:k8s_asset_scanner" + object: "component_instance:comp_1" + assertions: + can_view: true + can_write: true + - user: "user:keppel_scanner" + object: "component_instance:comp_1" + assertions: + can_view: true + can_write: false + - user: "user:alice" + object: "component_instance:comp_2" + assertions: + can_view: false diff --git a/internal/entity/component.go b/internal/entity/component.go index 1abd7b69..63d09818 100644 --- a/internal/entity/component.go +++ b/internal/entity/component.go @@ -16,6 +16,7 @@ type ComponentResult struct { *Component } +// @todo missing filter for serviceId/supportGroupId type ComponentFilter struct { Paginated CCRN []*string `json:"ccrn"` diff --git a/internal/entity/component_instance.go b/internal/entity/component_instance.go index 25d93931..08be713e 100644 --- a/internal/entity/component_instance.go +++ b/internal/entity/component_instance.go @@ -100,6 +100,7 @@ var AllComponentInstanceType = []string{ ComponentInstanceTypeProjectConfiguration.String(), } +// @todo missing filter for serviceId/supportGroupId type ComponentInstanceFilter struct { PaginatedX IssueMatchId []*int64 `json:"issue_match_id"` @@ -121,6 +122,7 @@ type ComponentInstanceFilter struct { Context []*Json `json:"context"` Search []*string `json:"search"` State []StateFilterType `json:"state"` + SupportGroup []*string `json:"support_group"` } type ComponentInstanceAggregations struct { diff --git a/internal/entity/component_version.go b/internal/entity/component_version.go index 39d5bd1c..f9a7b237 100644 --- a/internal/entity/component_version.go +++ b/internal/entity/component_version.go @@ -3,6 +3,7 @@ package entity +// @todo missing filter for serviceId/supportGroupId type ComponentVersionFilter struct { PaginatedX Id []*int64 `json:"id"` diff --git a/internal/entity/issue_match.go b/internal/entity/issue_match.go index dec241cc..9c5623bf 100644 --- a/internal/entity/issue_match.go +++ b/internal/entity/issue_match.go @@ -54,6 +54,7 @@ type IssueMatch struct { TargetRemediationDate time.Time `json:"target_remediation_date"` } +// @todo missing filter for serviceId/supportGroupId type IssueMatchFilter struct { PaginatedX Id []*int64 `json:"id"` diff --git a/internal/entity/support_group.go b/internal/entity/support_group.go index be1bd7e0..15c0d339 100644 --- a/internal/entity/support_group.go +++ b/internal/entity/support_group.go @@ -9,6 +9,7 @@ type SupportGroup struct { CCRN string `json:"ccrn"` } +// @todo think about parent for nesting support groups type SupportGroupFilter struct { Paginated Id []*int64 `json:"id"`