Skip to content

Commit 881c6df

Browse files
committed
Setup Regal to lint policies and clean them up
1 parent 0b3f5bc commit 881c6df

File tree

15 files changed

+401
-376
lines changed

15 files changed

+401
-376
lines changed

.github/workflows/ci.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ jobs:
3333
- name: Setup OPA
3434
uses: open-policy-agent/[email protected]
3535
with:
36-
version: 0.64.1
36+
version: 0.70.0
37+
38+
- name: Setup Regal
39+
uses: StyraInc/setup-regal@v1
40+
with:
41+
version: 0.29.2
3742

3843
- name: Lint policies
3944
working-directory: ./policies

.github/workflows/coverage.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- name: Setup OPA
3030
uses: open-policy-agent/[email protected]
3131
with:
32-
version: 0.64.1
32+
version: 0.70.0
3333

3434
- name: Run OPA tests with coverage
3535
working-directory: ./policies

policies/.regal/config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
rules:
2+
style:
3+
external-reference:
4+
level: ignore
5+
line-length:
6+
level: ignore

policies/Makefile

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
# Set to 1 to run OPA through Docker
22
DOCKER := 0
33
PODMAN := 0
4-
OPA_DOCKER_IMAGE := docker.io/openpolicyagent/opa:0.64.1-debug
4+
OPA_DOCKER_IMAGE := docker.io/openpolicyagent/opa:0.70.0-debug
5+
REGAL_DOCKER_IMAGE := ghcr.io/styrainc/regal:0.29.2
56

67
INPUTS := \
7-
client_registration.rego \
8-
register.rego \
9-
authorization_grant.rego \
10-
email.rego
8+
client_registration/client_registration.rego \
9+
register/register.rego \
10+
authorization_grant/authorization_grant.rego \
11+
email/email.rego
1112

1213
ifeq ($(DOCKER), 1)
1314
OPA := docker run -i -v $(shell pwd):/policies:ro -w /policies --rm $(OPA_DOCKER_IMAGE)
1415
OPA_RW := docker run -i -v $(shell pwd):/policies -w /policies --rm $(OPA_DOCKER_IMAGE)
16+
REGAL := docker run -i -v $(shell pwd):/policies:ro -w /policies --rm $(REGAL_DOCKER_IMAGE)
1517
else ifeq ($(PODMAN), 1)
1618
# When running rootless, the volume directory may need to be given global write permissions on the host
1719
OPA := podman run -i -v $(shell pwd):/policies:ro:Z -w /policies --rm $(OPA_DOCKER_IMAGE)
1820
OPA_RW := podman run -i -v $(shell pwd):/policies:Z -w /policies --rm $(OPA_DOCKER_IMAGE)
21+
REGAL := podman run -i -v $(shell pwd):/policies:ro:Z -w /policies --rm $(REGAL_DOCKER_IMAGE)
1922
else
2023
OPA := opa
2124
OPA_RW := opa
25+
REGAL := regal
2226
endif
2327

2428
policy.wasm: $(INPUTS)
@@ -38,16 +42,17 @@ fmt:
3842

3943
.PHONY: test
4044
test:
41-
$(OPA) test --schema ./schema/ -v ./*.rego
45+
$(OPA) test --schema ./schema/ --ignore schema -v ./
4246

4347
.PHONY: coverage
4448
coverage:
45-
$(OPA) test --coverage ./*.rego | $(OPA) eval --format pretty \
49+
$(OPA) test --coverage --schema ./schema/ --ignore schema ./ | $(OPA) eval --format pretty \
4650
--stdin-input \
4751
--data util/coveralls.rego \
4852
data.coveralls.from_opa > coverage.json
4953

5054
.PHONY: lint
5155
lint:
52-
$(OPA) fmt -d --fail ./*.rego util/*.rego
53-
$(OPA) check --strict --schema schema/ ./*.rego util/*.rego
56+
$(OPA) fmt -d --fail .
57+
$(OPA) check --strict --schema schema/ --ignore schema .
58+
$(REGAL) lint .

policies/authorization_grant.rego renamed to policies/authorization_grant/authorization_grant.rego

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,39 @@
33
# - input: schema["authorization_grant_input"]
44
package authorization_grant
55

6-
import future.keywords.in
6+
import rego.v1
77

88
default allow := false
99

10-
allow {
10+
allow if {
1111
count(violation) == 0
1212
}
1313

1414
# Users can request admin scopes if either:
1515
# 1. They are in the admin_users list
16-
can_request_admin(user) {
16+
can_request_admin(user) if {
1717
some admin_user in data.admin_users
1818
user.username == admin_user
1919
}
2020

2121
# 2. They have the can_request_admin flag set to true
22-
can_request_admin(user) {
22+
can_request_admin(user) if {
2323
user.can_request_admin
2424
}
2525

26-
interactive_grant_type("authorization_code") = true
26+
interactive_grant_type("authorization_code") := true
2727

28-
interactive_grant_type("urn:ietf:params:oauth:grant-type:device_code") = true
28+
interactive_grant_type("urn:ietf:params:oauth:grant-type:device_code") := true
2929

3030
# Special case to make empty scope work
31-
allowed_scope("") = true
31+
allowed_scope("") := true
3232

33-
allowed_scope("openid") = true
33+
allowed_scope("openid") := true
3434

35-
allowed_scope("email") = true
35+
allowed_scope("email") := true
3636

3737
# This grants access to Synapse's admin API endpoints
38-
allowed_scope("urn:synapse:admin:*") {
38+
allowed_scope("urn:synapse:admin:*") if {
3939
# Synapse doesn't support user-less tokens yet, so access to the admin API
4040
# can only be used with an authorization_code grant or a device code grant
4141
# as the user is present
@@ -44,39 +44,41 @@ allowed_scope("urn:synapse:admin:*") {
4444
}
4545

4646
# This grants access to the /graphql API endpoint
47-
allowed_scope("urn:mas:graphql:*") = true
47+
allowed_scope("urn:mas:graphql:*") := true
4848

4949
# This makes it possible to query and do anything in the GraphQL API as an admin
50-
allowed_scope("urn:mas:admin") {
50+
allowed_scope("urn:mas:admin") if {
5151
interactive_grant_type(input.grant_type)
5252
can_request_admin(input.user)
5353
}
5454

5555
# This makes it possible to get the admin scope for clients that are allowed
56-
allowed_scope("urn:mas:admin") {
56+
allowed_scope("urn:mas:admin") if {
5757
input.grant_type == "client_credentials"
5858
some client in data.admin_clients
5959
input.client.id == client
6060
}
6161

62-
allowed_scope(scope) {
62+
allowed_scope(scope) if {
6363
# Grant access to the C-S API only if there is a user
6464
interactive_grant_type(input.grant_type)
65-
regex.match("^urn:matrix:org.matrix.msc2967.client:device:[A-Za-z0-9._~!$&'()*+,;=:@/-]{10,}$", scope)
65+
regex.match(`^urn:matrix:org.matrix.msc2967.client:device:[A-Za-z0-9._~!$&'()*+,;=:@/-]{10,}$`, scope)
6666
}
6767

68-
allowed_scope("urn:matrix:org.matrix.msc2967.client:api:*") {
68+
allowed_scope("urn:matrix:org.matrix.msc2967.client:api:*") if {
6969
# Grant access to the C-S API only if there is a user
7070
interactive_grant_type(input.grant_type)
7171
}
7272

73-
violation[{"msg": msg}] {
73+
# METADATA
74+
# entrypoint: true
75+
violation contains {"msg": msg} if {
7476
some scope in split(input.scope, " ")
7577
not allowed_scope(scope)
7678
msg := sprintf("scope '%s' not allowed", [scope])
7779
}
7880

79-
violation[{"msg": "only one device scope is allowed at a time"}] {
81+
violation contains {"msg": "only one device scope is allowed at a time"} if {
8082
scope_list := split(input.scope, " ")
81-
count({key | scope_list[key]; startswith(scope_list[key], "urn:matrix:org.matrix.msc2967.client:device:")}) > 1
83+
count({scope | some scope in scope_list; startswith(scope, "urn:matrix:org.matrix.msc2967.client:device:")}) > 1
8284
}

policies/authorization_grant_test.rego renamed to policies/authorization_grant/authorization_grant_test.rego

Lines changed: 37 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,134 @@
1-
package authorization_grant
1+
package authorization_grant_test
2+
3+
import data.authorization_grant
4+
import rego.v1
25

36
user := {"username": "john"}
47

58
client := {"client_id": "client"}
69

7-
test_standard_scopes {
8-
allow with input.user as user
10+
test_standard_scopes if {
11+
authorization_grant.allow with input.user as user
912
with input.client as client
1013
with input.scope as ""
1114

12-
allow with input.user as user
15+
authorization_grant.allow with input.user as user
1316
with input.client as client
1417
with input.scope as "openid"
1518

16-
allow with input.user as user
19+
authorization_grant.allow with input.user as user
1720
with input.client as client
1821
with input.scope as "email"
1922

20-
allow with input.user as user
23+
authorization_grant.allow with input.user as user
2124
with input.client as client
2225
with input.scope as "openid email"
2326

2427
# Not supported yet
25-
not allow with input.user as user
28+
not authorization_grant.allow with input.user as user
2629
with input.client as client
2730
with input.scope as "phone"
2831

2932
# Not supported yet
30-
not allow with input.user as user
33+
not authorization_grant.allow with input.user as user
3134
with input.client as client
3235
with input.scope as "profile"
3336
}
3437

35-
test_matrix_scopes {
36-
allow with input.user as user
38+
test_matrix_scopes if {
39+
authorization_grant.allow with input.user as user
3740
with input.client as client
3841
with input.grant_type as "authorization_code"
3942
with input.scope as "urn:matrix:org.matrix.msc2967.client:api:*"
4043

41-
allow with input.user as user
44+
authorization_grant.allow with input.user as user
4245
with input.client as client
4346
with input.grant_type as "urn:ietf:params:oauth:grant-type:device_code"
4447
with input.scope as "urn:matrix:org.matrix.msc2967.client:api:*"
4548

46-
not allow with input.user as user
49+
not authorization_grant.allow with input.user as user
4750
with input.client as client
4851
with input.grant_type as "client_credentials"
4952
with input.scope as "urn:matrix:org.matrix.msc2967.client:api:*"
5053
}
5154

52-
test_device_scopes {
53-
allow with input.user as user
55+
test_device_scopes if {
56+
authorization_grant.allow with input.user as user
5457
with input.client as client
5558
with input.grant_type as "authorization_code"
5659
with input.scope as "urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd01"
5760

58-
allow with input.user as user
61+
authorization_grant.allow with input.user as user
5962
with input.client as client
6063
with input.grant_type as "authorization_code"
6164
with input.scope as "urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd01-asdasdsa1-2313"
6265

6366
# Too short
64-
not allow with input.user as user
67+
not authorization_grant.allow with input.user as user
6568
with input.client as client
6669
with input.grant_type as "authorization_code"
6770
with input.scope as "urn:matrix:org.matrix.msc2967.client:device:abcd"
6871

6972
# Multiple device scope
70-
not allow with input.user as user
73+
not authorization_grant.allow with input.user as user
7174
with input.client as client
7275
with input.grant_type as "authorization_code"
7376
with input.scope as "urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd01 urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd02"
7477

7578
# Allowed with the device code grant
76-
allow with input.user as user
79+
authorization_grant.allow with input.user as user
7780
with input.client as client
7881
with input.grant_type as "urn:ietf:params:oauth:grant-type:device_code"
7982
with input.scope as "urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd01"
8083

81-
# Not allowed for the client credentials grant
82-
not allow with input.client as client
84+
# Not authorization_grant.allowed for the client credentials grant
85+
not authorization_grant.allow with input.client as client
8386
with input.grant_type as "client_credentials"
8487
with input.scope as "urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd01"
8588
}
8689

87-
test_synapse_admin_scopes {
88-
allow with input.user as user
89-
with input.client as client
90-
with data.admin_users as ["john"]
91-
with input.grant_type as "authorization_code"
92-
with input.scope as "urn:synapse:admin:*"
90+
test_synapse_admin_scopes if {
91+
some grant_type in ["authorization_code", "urn:ietf:params:oauth:grant-type:device_code"]
9392

94-
allow with input.user as user
93+
authorization_grant.allow with input.user as user
9594
with input.client as client
9695
with data.admin_users as ["john"]
97-
with input.grant_type as "urn:ietf:params:oauth:grant-type:device_code"
98-
with input.scope as "urn:synapse:admin:*"
99-
100-
not allow with input.user as user
101-
with input.client as client
102-
with data.admin_users as []
103-
with input.grant_type as "authorization_code"
104-
with input.scope as "urn:synapse:admin:*"
105-
106-
not allow with input.user as user
107-
with input.client as client
108-
with data.admin_users as []
109-
with input.grant_type as "urn:ietf:params:oauth:grant-type:device_code"
96+
with input.grant_type as grant_type
11097
with input.scope as "urn:synapse:admin:*"
11198

112-
allow with input.user as user
113-
with input.user.can_request_admin as true
99+
not authorization_grant.allow with input.user as user
114100
with input.client as client
115101
with data.admin_users as []
116-
with input.grant_type as "authorization_code"
102+
with input.grant_type as grant_type
117103
with input.scope as "urn:synapse:admin:*"
118104

119-
allow with input.user as user
105+
authorization_grant.allow with input.user as user
120106
with input.user.can_request_admin as true
121107
with input.client as client
122108
with data.admin_users as []
123-
with input.grant_type as "urn:ietf:params:oauth:grant-type:device_code"
109+
with input.grant_type as grant_type
124110
with input.scope as "urn:synapse:admin:*"
125111

126-
not allow with input.user as user
112+
not authorization_grant.allow with input.user as user
127113
with input.user.can_request_admin as false
128114
with input.client as client
129115
with data.admin_users as []
130-
with input.grant_type as "authorization_code"
131-
with input.scope as "urn:synapse:admin:*"
132-
133-
not allow with input.user as user
134-
with input.user.can_request_admin as false
135-
with input.client as client
136-
with data.admin_users as []
137-
with input.grant_type as "urn:ietf:params:oauth:grant-type:device_code"
116+
with input.grant_type as grant_type
138117
with input.scope as "urn:synapse:admin:*"
139118
}
140119

141-
test_mas_scopes {
142-
allow with input.user as user
120+
test_mas_scopes if {
121+
authorization_grant.allow with input.user as user
143122
with input.client as client
144123
with input.scope as "urn:mas:graphql:*"
145124

146-
allow with input.user as user
125+
authorization_grant.allow with input.user as user
147126
with input.client as client
148127
with data.admin_users as ["john"]
149128
with input.grant_type as "authorization_code"
150129
with input.scope as "urn:mas:admin"
151130

152-
not allow with input.user as user
131+
not authorization_grant.allow with input.user as user
153132
with input.client as client
154133
with data.admin_users as []
155134
with input.grant_type as "authorization_code"

0 commit comments

Comments
 (0)