Skip to content

chore: bump github.com/open-policy-agent/opa from 0.70.0 to 1.0.0 #16013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion coderd/rbac/authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

"github.com/ammario/tlru"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/v1/rego"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"go.opentelemetry.io/otel/attribute"
Expand Down
2 changes: 1 addition & 1 deletion coderd/rbac/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"flag"
"fmt"

"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/topdown"
"github.com/open-policy-agent/opa/v1/rego"
"golang.org/x/xerrors"

"github.com/coder/coder/v2/coderd/httpapi/httpapiconstraints"
Expand Down
151 changes: 84 additions & 67 deletions coderd/rbac/policy.rego
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package authz
import future.keywords

import rego.v1
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opting into rego.v1


# A great playground: https://play.openpolicyagent.org/
# Helpful cli commands to debug.
# opa eval --format=pretty 'data.authz.allow' -d policy.rego -i input.json
Expand Down Expand Up @@ -29,67 +31,74 @@ import future.keywords

# bool_flip lets you assign a value to an inverted bool.
# You cannot do 'x := !false', but you can do 'x := bool_flip(false)'
bool_flip(b) = flipped {
b
flipped = false
bool_flip(b) := flipped if {
b
flipped = false
}

bool_flip(b) = flipped {
not b
flipped = true
bool_flip(b) := flipped if {
not b
flipped = true
}

# number is a quick way to get a set of {true, false} and convert it to
# -1: {false, true} or {false}
# 0: {}
# 1: {true}
number(set) = c {
number(set) := c if {
count(set) == 0
c := 0
c := 0
}

number(set) = c {
number(set) := c if {
false in set
c := -1
c := -1
}

number(set) = c {
number(set) := c if {
not false in set
set[_]
c := 1
c := 1
}

# site, org, and user rules are all similar. Each rule should return a number
# from [-1, 1]. The number corresponds to "negative", "abstain", and "positive"
# for the given level. See the 'allow' rules for how these numbers are used.
default site = 0
default site := 0

site := site_allow(input.subject.roles)

default scope_site := 0

scope_site := site_allow([input.subject.scope])

site_allow(roles) := num {
site_allow(roles) := num if {
# allow is a set of boolean values without duplicates.
allow := { x |
allow := {x |
# Iterate over all site permissions in all roles
perm := roles[_].site[_]
perm.action in [input.action, "*"]
perm := roles[_].site[_]
perm.action in [input.action, "*"]
perm.resource_type in [input.object.type, "*"]

# x is either 'true' or 'false' if a matching permission exists.
x := bool_flip(perm.negate)
}
num := number(allow)
x := bool_flip(perm.negate)
}
num := number(allow)
}

# org_members is the list of organizations the actor is apart of.
org_members := { orgID |
org_members := {orgID |
input.subject.roles[_].org[orgID]
}

# org is the same as 'site' except we need to iterate over each organization
# that the actor is a member of.
default org = 0
default org := 0

org := org_allow(input.subject.roles)

default scope_org := 0

scope_org := org_allow([input.scope])

# org_allow_set is a helper function that iterates over all orgs that the actor
Expand All @@ -102,10 +111,10 @@ scope_org := org_allow([input.scope])
# The reason we calculate this for all orgs, and not just the input.object.org_owner
# is that sometimes the input.object.org_owner is unknown. In those cases
# we have a list of org_ids that can we use in a SQL 'WHERE' clause.
org_allow_set(roles) := allow_set {
allow_set := { id: num |
org_allow_set(roles) := allow_set if {
allow_set := {id: num |
id := org_members[_]
set := { x |
set := {x |
perm := roles[_].org[id][_]
perm.action in [input.action, "*"]
perm.resource_type in [input.object.type, "*"]
Expand All @@ -115,7 +124,7 @@ org_allow_set(roles) := allow_set {
}
}

org_allow(roles) := num {
org_allow(roles) := num if {
# If the object has "any_org" set to true, then use the other
# org_allow block.
not input.object.any_org
Expand All @@ -135,78 +144,82 @@ org_allow(roles) := num {
# This is useful for UI elements when we want to conclude, "Can the user create
# a new template in any organization?"
# It is easier than iterating over every organization the user is apart of.
org_allow(roles) := num {
org_allow(roles) := num if {
input.object.any_org # if this is false, this code block is not used
allow := org_allow_set(roles)


# allow is a map of {"<org_id>": <number>}. We only care about values
# that are 1, and ignore the rest.
num := number([
keep |
# for every value in the mapping
value := allow[_]
# only keep values > 0.
# 1 = allow, 0 = abstain, -1 = deny
# We only need 1 explicit allow to allow the action.
# deny's and abstains are intentionally ignored.
value > 0
# result set is a set of [true,false,...]
# which "number()" will convert to a number.
keep := true
keep |
# for every value in the mapping
value := allow[_]

# only keep values > 0.
# 1 = allow, 0 = abstain, -1 = deny
# We only need 1 explicit allow to allow the action.
# deny's and abstains are intentionally ignored.
value > 0

# result set is a set of [true,false,...]
# which "number()" will convert to a number.
keep := true
])
}

# 'org_mem' is set to true if the user is an org member
# If 'any_org' is set to true, use the other block to determine org membership.
org_mem := true {
org_mem if {
not input.object.any_org
input.object.org_owner != ""
input.object.org_owner in org_members
}

org_mem := true {
org_mem if {
input.object.any_org
count(org_members) > 0
}

org_ok {
org_ok if {
org_mem
}

# If the object has no organization, then the user is also considered part of
# the non-existent org.
org_ok {
org_ok if {
input.object.org_owner == ""
not input.object.any_org
}

# User is the same as the site, except it only applies if the user owns the object and
# the user is apart of the org (if the object has an org).
default user = 0
default user := 0

user := user_allow(input.subject.roles)

default user_scope := 0

scope_user := user_allow([input.scope])

user_allow(roles) := num {
input.object.owner != ""
input.subject.id = input.object.owner
allow := { x |
perm := roles[_].user[_]
perm.action in [input.action, "*"]
user_allow(roles) := num if {
input.object.owner != ""
input.subject.id = input.object.owner
allow := {x |
perm := roles[_].user[_]
perm.action in [input.action, "*"]
perm.resource_type in [input.object.type, "*"]
x := bool_flip(perm.negate)
}
num := number(allow)
x := bool_flip(perm.negate)
}
num := number(allow)
}

# Scope allow_list is a list of resource IDs explicitly allowed by the scope.
# If the list is '*', then all resources are allowed.
scope_allow_list {
scope_allow_list if {
"*" in input.subject.scope.allow_list
}

scope_allow_list {
scope_allow_list if {
# If the wildcard is listed in the allow_list, we do not care about the
# object.id. This line is included to prevent partial compilations from
# ever needing to include the object.id.
Expand All @@ -226,66 +239,70 @@ scope_allow_list {
# Allow query:
# data.authz.role_allow = true data.authz.scope_allow = true

role_allow {
role_allow if {
site = 1
}

role_allow {
role_allow if {
not site = -1
org = 1
}

role_allow {
role_allow if {
not site = -1
not org = -1

# If we are not a member of an org, and the object has an org, then we are
# not authorized. This is an "implied -1" for not being in the org.
org_ok
user = 1
}

scope_allow {
scope_allow if {
scope_allow_list
scope_site = 1
}

scope_allow {
scope_allow if {
scope_allow_list
not scope_site = -1
scope_org = 1
}

scope_allow {
scope_allow if {
scope_allow_list
not scope_site = -1
not scope_org = -1

# If we are not a member of an org, and the object has an org, then we are
# not authorized. This is an "implied -1" for not being in the org.
org_ok
scope_user = 1
}

# ACL for users
acl_allow {
acl_allow if {
# Should you have to be a member of the org too?
perms := input.object.acl_user_list[input.subject.id]

# Either the input action or wildcard
[input.action, "*"][_] in perms
}

# ACL for groups
acl_allow {
acl_allow if {
# If there is no organization owner, the object cannot be owned by an
# org_scoped team.
org_mem
group := input.subject.groups[_]
perms := input.object.acl_group_list[group]

# Either the input action or wildcard
[input.action, "*"][_] in perms
}

# ACL for 'all_users' special group
acl_allow {
acl_allow if {
org_mem
perms := input.object.acl_group_list[input.object.org_owner]
[input.action, "*"][_] in perms
Expand All @@ -296,13 +313,13 @@ acl_allow {
# The role or the ACL must allow the action. Scopes can be used to limit,
# so scope_allow must always be true.

allow {
allow if {
role_allow
scope_allow
}

# ACL list must also have the scope_allow to pass
allow {
allow if {
acl_allow
scope_allow
}
2 changes: 1 addition & 1 deletion coderd/rbac/regosql/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strings"

"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/v1/rego"
"golang.org/x/xerrors"

"github.com/coder/coder/v2/coderd/rbac/regosql/sqltypes"
Expand Down
2 changes: 1 addition & 1 deletion coderd/rbac/regosql/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"

"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/v1/rego"
"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/coderd/rbac/regosql"
Expand Down
Loading
Loading