Refactor Rego filters WRT organizations (#10387)
This changes how filters are defined in Rego rules in two major ways: * Instead of reverse polish notation, filters are now combined by using Lisp-like prefix notation: `[foo, bar, "|", baz, "|"]` is now `["|", foo, bar, baz]`. Subjectively, I find this more readable, especially in complex expressions, because it's easier to see which operands correspond to which operator. It also makes it easier to combine an arbitrary amount of filters using Rego (it's just `array.concat([op], filters)`), which enables the second change: * Instead of manually writing out filters that check that a resource belongs to an organization, add a generic function, `add_organization_filter`, that automatically adds the necessary filters given the list of organization ID lookups. This eliminates a lot of duplicate logic.
This commit is contained in:
@@ -21,6 +21,9 @@ rules:
|
||||
# Mainly a style preference
|
||||
# https://docs.styra.com/regal/rules/style/avoid-get-and-list-prefix
|
||||
level: ignore
|
||||
external-reference:
|
||||
# https://docs.styra.com/regal/rules/style/external-reference
|
||||
level: ignore
|
||||
opa-fmt:
|
||||
# https://docs.styra.com/regal/rules/style/opa-fmt
|
||||
level: ignore
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
### Changed
|
||||
|
||||
- The format for filters in Rego policy files has changed; if you have
|
||||
added custom policy files, you may need to update them
|
||||
(<https://github.com/cvat-ai/cvat/pull/10387>)
|
||||
@@ -50,9 +50,7 @@ allow if {
|
||||
utils.is_resource_owner
|
||||
}
|
||||
|
||||
q_user_is_owner(user) := [
|
||||
{"owner_id": user.id},
|
||||
]
|
||||
q_user_is_owner(user) := {"owner_id": user.id}
|
||||
|
||||
# Django Q object to filter list of entries
|
||||
filter := q_user_is_owner(input.auth.user)
|
||||
|
||||
@@ -57,48 +57,33 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"task__project__organization": org.id}, "|",
|
||||
]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"task__owner_id": user.id},
|
||||
{"task__assignee_id": user.id}, "|",
|
||||
{"task__project__owner_id": user.id}, "|",
|
||||
{"task__project__assignee_id": user.id}, "|",
|
||||
{"task__assignee_id": user.id},
|
||||
{"task__project__owner_id": user.id},
|
||||
{"task__project__assignee_id": user.id},
|
||||
]
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"task__project__organization": org.id}, "|",
|
||||
]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"task__project__organization": org.id}, "|",
|
||||
|
||||
qobject := ["|",
|
||||
{"task__owner_id": user.id},
|
||||
{"task__assignee_id": user.id}, "|",
|
||||
{"task__project__owner_id": user.id}, "|",
|
||||
{"task__project__assignee_id": user.id}, "|",
|
||||
|
||||
"&"
|
||||
{"task__assignee_id": user.id},
|
||||
{"task__project__owner_id": user.id},
|
||||
{"task__project__assignee_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"task__organization",
|
||||
"task__project__organization",
|
||||
])
|
||||
|
||||
@@ -59,24 +59,21 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
qobject := [ {"organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.SUPERVISOR)
|
||||
qobject := [ {"organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
qobject := [ {"owner": input.auth.user.id} ]
|
||||
qobject := {"owner": input.auth.user.id}
|
||||
} else := qobject if {
|
||||
utils.is_organization
|
||||
qobject := [ {"owner": input.auth.user.id}, {"organization": input.auth.organization.id}, "&" ]
|
||||
qobject := {"owner": input.auth.user.id}
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["organization"])
|
||||
|
||||
allow if {
|
||||
input.scope in {utils.VIEW, utils.LIST_CONTENT}
|
||||
utils.is_sandbox
|
||||
|
||||
@@ -164,57 +164,45 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"issue__job__segment__task__organization": org.id},
|
||||
{"issue__job__segment__task__project__organization": org.id}, "|"
|
||||
]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"owner": user.id},
|
||||
{"issue__owner": user.id}, "|",
|
||||
{"issue__assignee": user.id}, "|",
|
||||
{"issue__job__assignee": user.id}, "|",
|
||||
{"issue__job__segment__task__owner": user.id}, "|",
|
||||
{"issue__job__segment__task__assignee": user.id}, "|",
|
||||
{"issue__job__segment__task__project__owner": user.id}, "|",
|
||||
{"issue__job__segment__task__project__assignee": user.id}, "|"
|
||||
{"issue__owner": user.id},
|
||||
{"issue__assignee": user.id},
|
||||
{"issue__job__assignee": user.id},
|
||||
{"issue__job__segment__task__owner": user.id},
|
||||
{"issue__job__segment__task__assignee": user.id},
|
||||
{"issue__job__segment__task__project__owner": user.id},
|
||||
{"issue__job__segment__task__project__assignee": user.id},
|
||||
]
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"issue__job__segment__task__organization": org.id},
|
||||
{"issue__job__segment__task__project__organization": org.id}, "|"
|
||||
]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"owner": user.id},
|
||||
{"issue__owner": user.id}, "|",
|
||||
{"issue__assignee": user.id}, "|",
|
||||
{"issue__job__assignee": user.id}, "|",
|
||||
{"issue__job__segment__task__owner": user.id}, "|",
|
||||
{"issue__job__segment__task__assignee": user.id}, "|",
|
||||
{"issue__job__segment__task__project__owner": user.id}, "|",
|
||||
{"issue__job__segment__task__project__assignee": user.id}, "|",
|
||||
{"issue__job__segment__task__organization": org.id},
|
||||
{"issue__job__segment__task__project__organization": org.id}, "|", "&"
|
||||
{"issue__owner": user.id},
|
||||
{"issue__assignee": user.id},
|
||||
{"issue__job__assignee": user.id},
|
||||
{"issue__job__segment__task__owner": user.id},
|
||||
{"issue__job__segment__task__assignee": user.id},
|
||||
{"issue__job__segment__task__project__owner": user.id},
|
||||
{"issue__job__segment__task__project__assignee": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"issue__job__segment__task__organization",
|
||||
"issue__job__segment__task__project__organization",
|
||||
])
|
||||
|
||||
allow if {
|
||||
input.scope == utils.VIEW
|
||||
utils.is_sandbox
|
||||
|
||||
@@ -157,53 +157,43 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"job__segment__task__organization": org.id},
|
||||
{"job__segment__task__project__organization": org.id}, "|"
|
||||
]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
{"owner": user.id}, {"assignee": user.id}, "|",
|
||||
{"job__assignee": user.id}, "|",
|
||||
{"job__segment__task__owner": user.id}, "|",
|
||||
{"job__segment__task__assignee": user.id}, "|",
|
||||
{"job__segment__task__project__owner": user.id}, "|",
|
||||
{"job__segment__task__project__assignee": user.id}, "|"
|
||||
qobject := ["|",
|
||||
{"owner": user.id},
|
||||
{"assignee": user.id},
|
||||
{"job__assignee": user.id},
|
||||
{"job__segment__task__owner": user.id},
|
||||
{"job__segment__task__assignee": user.id},
|
||||
{"job__segment__task__project__owner": user.id},
|
||||
{"job__segment__task__project__assignee": user.id},
|
||||
]
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"job__segment__task__organization": org.id},
|
||||
{"job__segment__task__project__organization": org.id}, "|"
|
||||
]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"owner": user.id}, {"assignee": user.id}, "|",
|
||||
{"job__assignee": user.id}, "|",
|
||||
{"job__segment__task__owner": user.id}, "|",
|
||||
{"job__segment__task__assignee": user.id}, "|",
|
||||
{"job__segment__task__project__owner": user.id}, "|",
|
||||
{"job__segment__task__project__assignee": user.id}, "|",
|
||||
{"job__segment__task__organization": org.id},
|
||||
{"job__segment__task__project__organization": org.id}, "|", "&"
|
||||
qobject := ["|",
|
||||
{"owner": user.id},
|
||||
{"assignee": user.id},
|
||||
{"job__assignee": user.id},
|
||||
{"job__segment__task__owner": user.id},
|
||||
{"job__segment__task__assignee": user.id},
|
||||
{"job__segment__task__project__owner": user.id},
|
||||
{"job__segment__task__project__assignee": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"job__segment__task__organization",
|
||||
"job__segment__task__project__organization",
|
||||
])
|
||||
|
||||
allow if {
|
||||
input.scope == utils.VIEW
|
||||
utils.is_sandbox
|
||||
|
||||
@@ -125,44 +125,39 @@ allow if {
|
||||
}
|
||||
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
qobject := [
|
||||
{"segment__task__organization": input.auth.organization.id},
|
||||
{"segment__task__project__organization": input.auth.organization.id}, "|" ]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"assignee_id": user.id},
|
||||
{"segment__task__owner_id": user.id}, "|",
|
||||
{"segment__task__assignee_id": user.id}, "|",
|
||||
{"segment__task__project__owner_id": user.id}, "|",
|
||||
{"segment__task__project__assignee_id": user.id}, "|"]
|
||||
} else := qobject if {
|
||||
{"segment__task__owner_id": user.id},
|
||||
{"segment__task__assignee_id": user.id},
|
||||
{"segment__task__project__owner_id": user.id},
|
||||
{"segment__task__project__assignee_id": user.id},
|
||||
]
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
qobject := [
|
||||
{"segment__task__organization": input.auth.organization.id},
|
||||
{"segment__task__project__organization": input.auth.organization.id}, "|"]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"assignee_id": user.id},
|
||||
{"segment__task__owner_id": user.id}, "|",
|
||||
{"segment__task__assignee_id": user.id}, "|",
|
||||
{"segment__task__project__owner_id": user.id}, "|",
|
||||
{"segment__task__project__assignee_id": user.id}, "|",
|
||||
{"segment__task__organization": input.auth.organization.id},
|
||||
{"segment__task__project__organization": input.auth.organization.id}, "|", "&"]
|
||||
{"segment__task__owner_id": user.id},
|
||||
{"segment__task__assignee_id": user.id},
|
||||
{"segment__task__project__owner_id": user.id},
|
||||
{"segment__task__project__assignee_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"segment__task__organization",
|
||||
"segment__task__project__organization",
|
||||
])
|
||||
|
||||
allow if {
|
||||
input.scope in {utils.CREATE, utils.DELETE}
|
||||
utils.has_perm(utils.USER)
|
||||
|
||||
@@ -57,42 +57,33 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"project__organization": org.id}, "|",
|
||||
]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"task__owner_id": user.id},
|
||||
{"task__assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|",
|
||||
{"project__assignee_id": user.id}, "|",
|
||||
{"task__assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"project__organization": org.id}, "|",
|
||||
]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"task__owner_id": user.id},
|
||||
{"task__assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|",
|
||||
{"project__assignee_id": user.id}, "|",
|
||||
{"task__assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"task__organization",
|
||||
"project__organization",
|
||||
])
|
||||
|
||||
@@ -86,29 +86,24 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
qobject := [ {"organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"assignee_id": user.id}, "|" ]
|
||||
} else := qobject if {
|
||||
qobject := ["|", {"owner_id": user.id}, {"assignee_id": user.id}]
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
qobject := [ {"organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"assignee_id": user.id}, "|",
|
||||
{"organization": input.auth.organization.id}, "&" ]
|
||||
qobject := ["|", {"owner_id": user.id}, {"assignee_id": user.id}]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["organization"])
|
||||
|
||||
allow if {
|
||||
input.scope == utils.VIEW
|
||||
utils.is_sandbox
|
||||
|
||||
@@ -152,34 +152,33 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
qobject := [ {"organization": input.auth.organization.id},
|
||||
{"project__organization": input.auth.organization.id}, "|"]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|", {"project__assignee_id": user.id}, "|"]
|
||||
} else := qobject if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
qobject := ["|",
|
||||
{"owner_id": user.id},
|
||||
{"assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
} else := {} if {
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
qobject := [ {"organization": input.auth.organization.id},
|
||||
{"project__organization": input.auth.organization.id}, "|"]
|
||||
utils.has_perm(utils.USER)
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|", {"project__assignee_id": user.id}, "|",
|
||||
{"organization": input.auth.organization.id},
|
||||
{"project__organization": input.auth.organization.id}, "|", "&"]
|
||||
qobject := ["|",
|
||||
{"owner_id": user.id},
|
||||
{"assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["organization", "project__organization"])
|
||||
|
||||
allow if {
|
||||
input.scope in {
|
||||
utils.VIEW, utils.VIEW_ANNOTATIONS, utils.EXPORT_DATASET, utils.VIEW_METADATA,
|
||||
|
||||
@@ -46,17 +46,17 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
qobject := [ {"id": input.auth.user.id} ]
|
||||
} else := qobject if {
|
||||
org_id := input.auth.organization.id
|
||||
qobject := [ {"memberships__organization": org_id} ]
|
||||
qobject := {"id": input.auth.user.id}
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["memberships__organization"])
|
||||
|
||||
allow if {
|
||||
input.scope == utils.VIEW
|
||||
input.resource.id == input.auth.user.id
|
||||
|
||||
@@ -55,24 +55,20 @@ allow if {
|
||||
}
|
||||
|
||||
|
||||
filter := [] if {
|
||||
base_filter := {} if {
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
qobject := [ {"org_id": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
qobject := [ {"user_id": input.auth.user.id} ]
|
||||
} else := qobject if {
|
||||
qobject := {"user_id": input.auth.user.id}
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
qobject := [ {"org_id": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
qobject := [ {"user_id": input.auth.user.id}, {"org_id": input.auth.organization.id} ]
|
||||
qobject := {"user_id": input.auth.user.id}
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["org_id"])
|
||||
|
||||
@@ -9,7 +9,7 @@ import operator
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from collections.abc import Sequence
|
||||
from enum import Enum
|
||||
from functools import cached_property
|
||||
from functools import cached_property, reduce
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, TypeAlias, TypeVar
|
||||
|
||||
@@ -241,33 +241,32 @@ class OpenPolicyAgentPermission(metaclass=ABCMeta):
|
||||
with make_requests_session() as session:
|
||||
r = session.post(url, json=self.payload).json()["result"]
|
||||
|
||||
q_objects = []
|
||||
ops_dict = {
|
||||
binary_ops_dict = {
|
||||
"|": operator.or_,
|
||||
"&": operator.and_,
|
||||
"~": operator.not_,
|
||||
}
|
||||
for item in r:
|
||||
if isinstance(item, str):
|
||||
val1 = q_objects.pop()
|
||||
if item == "~":
|
||||
q_objects.append(ops_dict[item](val1))
|
||||
else:
|
||||
val2 = q_objects.pop()
|
||||
q_objects.append(ops_dict[item](val1, val2))
|
||||
else:
|
||||
q_objects.append(Q(**item))
|
||||
|
||||
if q_objects:
|
||||
assert len(q_objects) == 1
|
||||
else:
|
||||
q_objects.append(Q())
|
||||
def parse_filter(expr):
|
||||
match expr:
|
||||
case ["~", arg]:
|
||||
return ~parse_filter(arg)
|
||||
case [op, *args]:
|
||||
return reduce(binary_ops_dict[op], map(parse_filter, args))
|
||||
case {} if not expr:
|
||||
# Empty Q() exhibits some bizarre behavior when used in expressions
|
||||
# (e.g. ~Q() works the same as Q()), so we use this as a more predictable
|
||||
# "always true" filter.
|
||||
return ~Q(pk__in=[])
|
||||
case {}:
|
||||
return Q(**expr)
|
||||
case _:
|
||||
assert False, "unknown expression type"
|
||||
|
||||
# By default, a QuerySet will not eliminate duplicate rows. If your
|
||||
# query spans multiple tables (e.g. members__user_id, owner_id), it's
|
||||
# possible to get duplicate results when a QuerySet is evaluated.
|
||||
# That's when you'd use distinct().
|
||||
return queryset.filter(q_objects[0]).distinct()
|
||||
return queryset.filter(parse_filter(r)).distinct()
|
||||
|
||||
@classmethod
|
||||
def get_per_field_update_scopes(cls, request, scopes_per_field):
|
||||
|
||||
@@ -101,3 +101,16 @@ is_sandbox if {
|
||||
is_organization if {
|
||||
input.auth.organization != null
|
||||
}
|
||||
|
||||
add_organization_filter(base_filter, organization_fields) := base_filter if is_sandbox
|
||||
|
||||
add_organization_filter(base_filter, organization_fields) := qobject if {
|
||||
is_organization
|
||||
qobject := ["&", base_filter, make_organization_filter(organization_fields)]
|
||||
}
|
||||
|
||||
make_organization_filter(organization_fields) := qobject if {
|
||||
is_array(organization_fields)
|
||||
count(organization_fields) > 0
|
||||
qobject := array.concat(["|"], [{f: input.auth.organization.id} | some f in organization_fields])
|
||||
}
|
||||
|
||||
@@ -43,30 +43,33 @@ allow if {
|
||||
utils.has_perm(utils.WORKER)
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
qobject := [ {"organization": input.auth.organization.id},
|
||||
{"project__organization": input.auth.organization.id}, "|"]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|", {"project__assignee_id": user.id}, "|"]
|
||||
} else := qobject if {
|
||||
qobject := ["|",
|
||||
{"owner_id": user.id},
|
||||
{"assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
qobject := [ {"organization": input.auth.organization.id},
|
||||
{"project__organization": input.auth.organization.id}, "|"]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|", {"project__assignee_id": user.id}, "|",
|
||||
{"organization": input.auth.organization.id},
|
||||
{"project__organization": input.auth.organization.id}, "|", "&"]
|
||||
qobject := ["|",
|
||||
{"owner_id": user.id},
|
||||
{"assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"organization",
|
||||
"project__organization",
|
||||
])
|
||||
|
||||
@@ -46,30 +46,30 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
utils.is_sandbox
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner": user.id}, {"membership__user": user.id}, "|" ]
|
||||
} else := qobject if {
|
||||
utils.is_organization
|
||||
utils.is_admin
|
||||
qobject := [ {"membership__organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
qobject := ["|",
|
||||
{"owner": user.id},
|
||||
{"membership__user": user.id},
|
||||
]
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
organizations.is_staff
|
||||
utils.has_perm(utils.USER)
|
||||
qobject := [ {"membership__organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
utils.is_organization
|
||||
user := input.auth.user
|
||||
org_id := input.auth.organization.id
|
||||
qobject := [ {"owner": user.id}, {"membership__user": user.id}, "|",
|
||||
{"membership__organization": org_id}, "&" ]
|
||||
qobject := ["|",
|
||||
{"owner": user.id},
|
||||
{"membership__user": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["membership__organization"])
|
||||
|
||||
allow if {
|
||||
input.scope == utils.CREATE
|
||||
input.auth.organization.id == input.resource.organization.id
|
||||
|
||||
@@ -46,25 +46,22 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
qobject := [ {"user": input.auth.user.id}, {"is_active": true}, "&" ]
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
org_id := input.auth.organization.id
|
||||
qobject := [ {"organization": org_id} ]
|
||||
} else := qobject if {
|
||||
qobject := ["&",
|
||||
{"user": input.auth.user.id},
|
||||
{"is_active": true},
|
||||
]
|
||||
} else := {} if {
|
||||
organizations.is_staff
|
||||
org_id := input.auth.organization.id
|
||||
qobject := [ {"organization": org_id} ]
|
||||
} else := qobject if {
|
||||
org_id := input.auth.organization.id
|
||||
qobject := [ {"organization": org_id}, {"is_active": true}, "&" ]
|
||||
qobject := {"is_active": true}
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["organization"])
|
||||
|
||||
allow if {
|
||||
input.scope == utils.VIEW
|
||||
input.resource.is_active
|
||||
|
||||
@@ -69,11 +69,17 @@ allow if {
|
||||
utils.has_perm(utils.USER)
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
} else := qobject if {
|
||||
user := input.auth.user
|
||||
qobject := [{"members__user_id": user.id}, {"members__is_active": true}, "&", {"owner_id": user.id}, "|" ]
|
||||
qobject := ["|",
|
||||
["&",
|
||||
{"members__user_id": user.id},
|
||||
{"members__is_active": true},
|
||||
],
|
||||
{"owner_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
allow if {
|
||||
|
||||
@@ -58,51 +58,39 @@ allow if {
|
||||
}
|
||||
|
||||
|
||||
q_user_is_maintainer(user) := [
|
||||
q_user_is_maintainer(user) := ["|",
|
||||
{"report__job__segment__task__owner_id": user.id},
|
||||
{"report__job__segment__task__assignee_id": user.id}, "|",
|
||||
{"report__job__segment__task__project__owner_id": user.id}, "|",
|
||||
{"report__job__segment__task__project__assignee_id": user.id}, "|",
|
||||
{"report__task__owner_id": user.id}, "|",
|
||||
{"report__task__assignee_id": user.id}, "|",
|
||||
{"report__task__project__owner_id": user.id}, "|",
|
||||
{"report__task__project__assignee_id": user.id}, "|",
|
||||
{"report__project__owner_id": user.id}, "|",
|
||||
{"report__project__assignee_id": user.id}, "|",
|
||||
{"report__job__segment__task__assignee_id": user.id},
|
||||
{"report__job__segment__task__project__owner_id": user.id},
|
||||
{"report__job__segment__task__project__assignee_id": user.id},
|
||||
{"report__task__owner_id": user.id},
|
||||
{"report__task__assignee_id": user.id},
|
||||
{"report__task__project__owner_id": user.id},
|
||||
{"report__task__project__assignee_id": user.id},
|
||||
{"report__project__owner_id": user.id},
|
||||
{"report__project__assignee_id": user.id},
|
||||
]
|
||||
|
||||
q_object_has_org(org) := [
|
||||
{"report__job__segment__task__organization": org.id},
|
||||
{"report__job__segment__task__project__organization": org.id}, "|",
|
||||
{"report__task__organization": org.id}, "|",
|
||||
{"report__task__project__organization": org.id}, "|",
|
||||
{"report__project__organization": org.id}, "|",
|
||||
]
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
org := input.auth.organization
|
||||
qobject := q_object_has_org(org)
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := q_user_is_maintainer(user)
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
org := input.auth.organization
|
||||
qobject := q_object_has_org(org)
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
org := input.auth.organization
|
||||
qobject := array.concat(
|
||||
array.concat(q_object_has_org(org), q_user_is_maintainer(user)),
|
||||
["&"]
|
||||
)
|
||||
qobject := q_user_is_maintainer(user)
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"report__job__segment__task__organization",
|
||||
"report__job__segment__task__project__organization",
|
||||
"report__task__organization",
|
||||
"report__task__project__organization",
|
||||
"report__project__organization",
|
||||
])
|
||||
|
||||
@@ -88,54 +88,39 @@ allow if {
|
||||
}
|
||||
|
||||
|
||||
q_user_is_maintainer(user) := [
|
||||
q_user_is_maintainer(user) := ["|",
|
||||
{"job__segment__task__owner_id": user.id},
|
||||
{"job__segment__task__assignee_id": user.id}, "|",
|
||||
{"job__segment__task__project__owner_id": user.id}, "|",
|
||||
{"job__segment__task__project__assignee_id": user.id}, "|",
|
||||
{"task__owner_id": user.id}, "|",
|
||||
{"task__assignee_id": user.id}, "|",
|
||||
{"task__project__owner_id": user.id}, "|",
|
||||
{"task__project__assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|",
|
||||
{"project__assignee_id": user.id}, "|",
|
||||
{"job__segment__task__assignee_id": user.id},
|
||||
{"job__segment__task__project__owner_id": user.id},
|
||||
{"job__segment__task__project__assignee_id": user.id},
|
||||
{"task__owner_id": user.id},
|
||||
{"task__assignee_id": user.id},
|
||||
{"task__project__owner_id": user.id},
|
||||
{"task__project__assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
|
||||
q_object_has_org(org) := [
|
||||
{"job__segment__task__organization": org.id},
|
||||
{"job__segment__task__project__organization": org.id}, "|",
|
||||
{"task__organization": org.id}, "|",
|
||||
{"task__project__organization": org.id}, "|",
|
||||
{"project__organization": org.id}, "|",
|
||||
]
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
org := input.auth.organization
|
||||
qobject := q_object_has_org(org)
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := q_user_is_maintainer(user)
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
org := input.auth.organization
|
||||
qobject := q_object_has_org(org)
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
org := input.auth.organization
|
||||
qobject := array.concat(
|
||||
array.concat(
|
||||
q_object_has_org(org),
|
||||
q_user_is_maintainer(user),
|
||||
),
|
||||
["&"]
|
||||
)
|
||||
qobject := q_user_is_maintainer(user)
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"job__segment__task__organization",
|
||||
"job__segment__task__project__organization",
|
||||
"task__organization",
|
||||
"task__project__organization",
|
||||
"project__organization",
|
||||
])
|
||||
|
||||
@@ -57,55 +57,38 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"task__project__organization": org.id}, "|",
|
||||
{"project__organization": org.id}, "|",
|
||||
]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [
|
||||
qobject := ["|",
|
||||
{"task__owner_id": user.id},
|
||||
{"task__assignee_id": user.id}, "|",
|
||||
{"task__project__owner_id": user.id}, "|",
|
||||
{"task__project__assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|",
|
||||
{"project__assignee_id": user.id}, "|",
|
||||
{"task__assignee_id": user.id},
|
||||
{"task__project__owner_id": user.id},
|
||||
{"task__project__assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
} else := qobject if {
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.USER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"task__project__organization": org.id}, "|",
|
||||
{"project__organization": org.id}, "|",
|
||||
]
|
||||
} else := qobject if {
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
org := input.auth.organization
|
||||
qobject := [
|
||||
{"task__organization": org.id},
|
||||
{"task__project__organization": org.id}, "|",
|
||||
{"project__organization": org.id}, "|",
|
||||
|
||||
qobject := ["|",
|
||||
{"task__owner_id": user.id},
|
||||
{"task__assignee_id": user.id}, "|",
|
||||
{"task__project__owner_id": user.id}, "|",
|
||||
{"task__project__assignee_id": user.id}, "|",
|
||||
{"project__owner_id": user.id}, "|",
|
||||
{"project__assignee_id": user.id}, "|",
|
||||
|
||||
"&"
|
||||
{"task__assignee_id": user.id},
|
||||
{"task__project__owner_id": user.id},
|
||||
{"task__project__assignee_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
{"project__assignee_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, [
|
||||
"task__organization",
|
||||
"task__project__organization",
|
||||
"project__organization",
|
||||
])
|
||||
|
||||
@@ -65,31 +65,32 @@ allow if {
|
||||
organizations.is_member
|
||||
}
|
||||
|
||||
filter := [] if { # Django Q object to filter list of entries
|
||||
base_filter := {} if { # Django Q object to filter list of entries
|
||||
utils.is_admin
|
||||
utils.is_sandbox
|
||||
} else := qobject if {
|
||||
utils.is_admin
|
||||
utils.is_organization
|
||||
qobject := [ {"organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
utils.is_sandbox
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"project__owner_id": user.id}, "|" ]
|
||||
} else := qobject if {
|
||||
qobject := ["|",
|
||||
{"owner_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
]
|
||||
} else := {} if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.WORKER)
|
||||
organizations.has_perm(organizations.MAINTAINER)
|
||||
qobject := [ {"organization": input.auth.organization.id} ]
|
||||
} else := qobject if {
|
||||
utils.is_organization
|
||||
utils.has_perm(utils.WORKER)
|
||||
organizations.has_perm(organizations.WORKER)
|
||||
user := input.auth.user
|
||||
qobject := [ {"owner_id": user.id}, {"project__owner_id": user.id},
|
||||
"|", {"organization": input.auth.organization.id}, "&"]
|
||||
qobject := ["|",
|
||||
{"owner_id": user.id},
|
||||
{"project__owner_id": user.id},
|
||||
]
|
||||
}
|
||||
|
||||
filter := utils.add_organization_filter(base_filter, ["organization"])
|
||||
|
||||
|
||||
allow if {
|
||||
input.scope == utils.VIEW
|
||||
|
||||
Reference in New Issue
Block a user