gitlab-glaz 0.0.3-x86_64-linux-gnu → 1.0.0-x86_64-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +57 -59
- data/Cargo.toml +3 -2
- data/README.md +21 -37
- data/ext/glaz/Cargo.toml +1 -0
- data/ext/glaz/src/lib.rs +67 -14
- data/lib/gitlab/glaz/3.1/glaz.so +0 -0
- data/lib/gitlab/glaz/3.2/glaz.so +0 -0
- data/lib/gitlab/glaz/3.3/glaz.so +0 -0
- data/lib/gitlab/glaz/3.4/glaz.so +0 -0
- data/lib/gitlab/glaz/4.0/glaz.so +0 -0
- data/lib/gitlab/glaz/engine.rb +60 -0
- data/lib/gitlab/glaz/version.rb +1 -1
- data/lib/gitlab/glaz.rb +10 -11
- data/lib/proto/relationships/relationships_pb.rb +28 -0
- data/lib/proto/service_pb.rb +7 -5
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dfcae08928853d5919f115175a543775243e32ff7e37a46e2ac0ddb1d6bd1795
|
|
4
|
+
data.tar.gz: 1632f9fcfa5cd0334e3686b5b61dcb808b080545cceeb6986f47fcd8ad903fec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7ebe80491b18e91888fa8c4264dd38b51dba991b526161c7d615539d6bf65ae67414add414d09f910fdddeee4bec5100beaa0d5ac1075a04bef2af3dffb8de1b
|
|
7
|
+
data.tar.gz: ba98dd5097bf70272893f203665095f3590e5913fe65139be3f293c2e7b7fe0c6a2267f45aaa0424ac9496df88a8958b5d9d5604b11090b387aa2f4e5f724d67
|
data/Cargo.lock
CHANGED
|
@@ -244,10 +244,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
244
244
|
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
|
245
245
|
dependencies = [
|
|
246
246
|
"iana-time-zone",
|
|
247
|
-
"js-sys",
|
|
248
247
|
"num-traits",
|
|
249
248
|
"serde",
|
|
250
|
-
"wasm-bindgen",
|
|
251
249
|
"windows-link",
|
|
252
250
|
]
|
|
253
251
|
|
|
@@ -465,47 +463,21 @@ dependencies = [
|
|
|
465
463
|
|
|
466
464
|
[[package]]
|
|
467
465
|
name = "glaz"
|
|
468
|
-
version = "0.0
|
|
466
|
+
version = "1.0.0"
|
|
469
467
|
dependencies = [
|
|
470
468
|
"glaz-module",
|
|
471
|
-
"magnus",
|
|
472
|
-
]
|
|
473
|
-
|
|
474
|
-
[[package]]
|
|
475
|
-
name = "glaz-engine"
|
|
476
|
-
version = "0.1.0"
|
|
477
|
-
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=e1100ed8d93b3db58627229b7c4e16e29905a3d0#e1100ed8d93b3db58627229b7c4e16e29905a3d0"
|
|
478
|
-
dependencies = [
|
|
479
|
-
"async-trait",
|
|
480
|
-
"glaz-graph",
|
|
481
|
-
"glaz-policy",
|
|
482
469
|
"glaz-roles",
|
|
483
|
-
"
|
|
484
|
-
"serde_json",
|
|
485
|
-
]
|
|
486
|
-
|
|
487
|
-
[[package]]
|
|
488
|
-
name = "glaz-graph"
|
|
489
|
-
version = "0.1.0"
|
|
490
|
-
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=e1100ed8d93b3db58627229b7c4e16e29905a3d0#e1100ed8d93b3db58627229b7c4e16e29905a3d0"
|
|
491
|
-
dependencies = [
|
|
492
|
-
"anyhow",
|
|
493
|
-
"glaz-storage",
|
|
494
|
-
"uuid",
|
|
470
|
+
"magnus",
|
|
495
471
|
]
|
|
496
472
|
|
|
497
473
|
[[package]]
|
|
498
474
|
name = "glaz-module"
|
|
499
475
|
version = "0.1.0"
|
|
500
|
-
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=
|
|
476
|
+
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=13a32ad3f0e6490384afb6ba6a3c3e2a6439901a#13a32ad3f0e6490384afb6ba6a3c3e2a6439901a"
|
|
501
477
|
dependencies = [
|
|
502
|
-
"glaz-engine",
|
|
503
478
|
"glaz-policy",
|
|
504
479
|
"glaz-proto",
|
|
505
|
-
"glaz-roles",
|
|
506
|
-
"glaz-storage",
|
|
507
480
|
"prost",
|
|
508
|
-
"serde_json",
|
|
509
481
|
"thiserror",
|
|
510
482
|
"tokio",
|
|
511
483
|
"uuid",
|
|
@@ -514,12 +486,11 @@ dependencies = [
|
|
|
514
486
|
[[package]]
|
|
515
487
|
name = "glaz-policy"
|
|
516
488
|
version = "0.1.0"
|
|
517
|
-
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=
|
|
489
|
+
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=13a32ad3f0e6490384afb6ba6a3c3e2a6439901a#13a32ad3f0e6490384afb6ba6a3c3e2a6439901a"
|
|
518
490
|
dependencies = [
|
|
519
491
|
"async-trait",
|
|
520
492
|
"cedar-policy",
|
|
521
|
-
"glaz-
|
|
522
|
-
"glaz-storage",
|
|
493
|
+
"glaz-proto",
|
|
523
494
|
"serde_json",
|
|
524
495
|
"thiserror",
|
|
525
496
|
]
|
|
@@ -527,28 +498,21 @@ dependencies = [
|
|
|
527
498
|
[[package]]
|
|
528
499
|
name = "glaz-proto"
|
|
529
500
|
version = "0.1.0"
|
|
530
|
-
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=
|
|
501
|
+
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=13a32ad3f0e6490384afb6ba6a3c3e2a6439901a#13a32ad3f0e6490384afb6ba6a3c3e2a6439901a"
|
|
531
502
|
dependencies = [
|
|
532
503
|
"prost",
|
|
533
504
|
"prost-build",
|
|
505
|
+
"prost-types",
|
|
534
506
|
"protoc-bin-vendored",
|
|
535
507
|
]
|
|
536
508
|
|
|
537
509
|
[[package]]
|
|
538
510
|
name = "glaz-roles"
|
|
539
511
|
version = "0.1.0"
|
|
540
|
-
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=
|
|
541
|
-
|
|
542
|
-
[[package]]
|
|
543
|
-
name = "glaz-storage"
|
|
544
|
-
version = "0.1.0"
|
|
545
|
-
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=e1100ed8d93b3db58627229b7c4e16e29905a3d0#e1100ed8d93b3db58627229b7c4e16e29905a3d0"
|
|
512
|
+
source = "git+https://gitlab.com/gitlab-org/auth/glaz.git?rev=13a32ad3f0e6490384afb6ba6a3c3e2a6439901a#13a32ad3f0e6490384afb6ba6a3c3e2a6439901a"
|
|
546
513
|
dependencies = [
|
|
547
|
-
"async-trait",
|
|
548
|
-
"chrono",
|
|
549
|
-
"glaz-roles",
|
|
550
514
|
"serde",
|
|
551
|
-
"
|
|
515
|
+
"serde_yaml",
|
|
552
516
|
"thiserror",
|
|
553
517
|
"uuid",
|
|
554
518
|
]
|
|
@@ -705,7 +669,7 @@ dependencies = [
|
|
|
705
669
|
"ena",
|
|
706
670
|
"itertools 0.14.0",
|
|
707
671
|
"lalrpop-util",
|
|
708
|
-
"petgraph",
|
|
672
|
+
"petgraph 0.7.1",
|
|
709
673
|
"pico-args",
|
|
710
674
|
"regex",
|
|
711
675
|
"regex-syntax",
|
|
@@ -988,6 +952,17 @@ dependencies = [
|
|
|
988
952
|
"indexmap 2.13.1",
|
|
989
953
|
]
|
|
990
954
|
|
|
955
|
+
[[package]]
|
|
956
|
+
name = "petgraph"
|
|
957
|
+
version = "0.8.3"
|
|
958
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
959
|
+
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
|
960
|
+
dependencies = [
|
|
961
|
+
"fixedbitset",
|
|
962
|
+
"hashbrown 0.15.5",
|
|
963
|
+
"indexmap 2.13.1",
|
|
964
|
+
]
|
|
965
|
+
|
|
991
966
|
[[package]]
|
|
992
967
|
name = "phf_shared"
|
|
993
968
|
version = "0.11.3"
|
|
@@ -1053,9 +1028,9 @@ dependencies = [
|
|
|
1053
1028
|
|
|
1054
1029
|
[[package]]
|
|
1055
1030
|
name = "prost"
|
|
1056
|
-
version = "0.
|
|
1031
|
+
version = "0.14.4"
|
|
1057
1032
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1058
|
-
checksum = "
|
|
1033
|
+
checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1"
|
|
1059
1034
|
dependencies = [
|
|
1060
1035
|
"bytes",
|
|
1061
1036
|
"prost-derive",
|
|
@@ -1063,16 +1038,15 @@ dependencies = [
|
|
|
1063
1038
|
|
|
1064
1039
|
[[package]]
|
|
1065
1040
|
name = "prost-build"
|
|
1066
|
-
version = "0.
|
|
1041
|
+
version = "0.14.4"
|
|
1067
1042
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1068
|
-
checksum = "
|
|
1043
|
+
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
|
|
1069
1044
|
dependencies = [
|
|
1070
1045
|
"heck",
|
|
1071
|
-
"itertools 0.
|
|
1046
|
+
"itertools 0.13.0",
|
|
1072
1047
|
"log",
|
|
1073
1048
|
"multimap",
|
|
1074
|
-
"
|
|
1075
|
-
"petgraph",
|
|
1049
|
+
"petgraph 0.8.3",
|
|
1076
1050
|
"prettyplease",
|
|
1077
1051
|
"prost",
|
|
1078
1052
|
"prost-types",
|
|
@@ -1083,12 +1057,12 @@ dependencies = [
|
|
|
1083
1057
|
|
|
1084
1058
|
[[package]]
|
|
1085
1059
|
name = "prost-derive"
|
|
1086
|
-
version = "0.
|
|
1060
|
+
version = "0.14.4"
|
|
1087
1061
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1088
|
-
checksum = "
|
|
1062
|
+
checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf"
|
|
1089
1063
|
dependencies = [
|
|
1090
1064
|
"anyhow",
|
|
1091
|
-
"itertools 0.
|
|
1065
|
+
"itertools 0.13.0",
|
|
1092
1066
|
"proc-macro2",
|
|
1093
1067
|
"quote",
|
|
1094
1068
|
"syn",
|
|
@@ -1096,9 +1070,9 @@ dependencies = [
|
|
|
1096
1070
|
|
|
1097
1071
|
[[package]]
|
|
1098
1072
|
name = "prost-types"
|
|
1099
|
-
version = "0.
|
|
1073
|
+
version = "0.14.4"
|
|
1100
1074
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1101
|
-
checksum = "
|
|
1075
|
+
checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a"
|
|
1102
1076
|
dependencies = [
|
|
1103
1077
|
"prost",
|
|
1104
1078
|
]
|
|
@@ -1311,6 +1285,12 @@ version = "1.0.22"
|
|
|
1311
1285
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1312
1286
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
|
1313
1287
|
|
|
1288
|
+
[[package]]
|
|
1289
|
+
name = "ryu"
|
|
1290
|
+
version = "1.0.23"
|
|
1291
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1292
|
+
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
|
1293
|
+
|
|
1314
1294
|
[[package]]
|
|
1315
1295
|
name = "same-file"
|
|
1316
1296
|
version = "1.0.6"
|
|
@@ -1437,6 +1417,19 @@ dependencies = [
|
|
|
1437
1417
|
"syn",
|
|
1438
1418
|
]
|
|
1439
1419
|
|
|
1420
|
+
[[package]]
|
|
1421
|
+
name = "serde_yaml"
|
|
1422
|
+
version = "0.9.34+deprecated"
|
|
1423
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1424
|
+
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
|
1425
|
+
dependencies = [
|
|
1426
|
+
"indexmap 2.13.1",
|
|
1427
|
+
"itoa",
|
|
1428
|
+
"ryu",
|
|
1429
|
+
"serde",
|
|
1430
|
+
"unsafe-libyaml",
|
|
1431
|
+
]
|
|
1432
|
+
|
|
1440
1433
|
[[package]]
|
|
1441
1434
|
name = "sha3"
|
|
1442
1435
|
version = "0.10.8"
|
|
@@ -1550,7 +1543,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
1550
1543
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
|
1551
1544
|
dependencies = [
|
|
1552
1545
|
"fastrand",
|
|
1553
|
-
"getrandom",
|
|
1554
1546
|
"once_cell",
|
|
1555
1547
|
"rustix",
|
|
1556
1548
|
"windows-sys 0.61.2",
|
|
@@ -1720,6 +1712,12 @@ version = "0.2.6"
|
|
|
1720
1712
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1721
1713
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
|
1722
1714
|
|
|
1715
|
+
[[package]]
|
|
1716
|
+
name = "unsafe-libyaml"
|
|
1717
|
+
version = "0.2.11"
|
|
1718
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1719
|
+
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
|
1720
|
+
|
|
1723
1721
|
[[package]]
|
|
1724
1722
|
name = "uuid"
|
|
1725
1723
|
version = "1.23.0"
|
data/Cargo.toml
CHANGED
|
@@ -4,11 +4,12 @@ members = ["ext/*"]
|
|
|
4
4
|
resolver = "2"
|
|
5
5
|
|
|
6
6
|
[workspace.package]
|
|
7
|
-
version = "0.0
|
|
7
|
+
version = "1.0.0"
|
|
8
8
|
edition = "2024"
|
|
9
9
|
|
|
10
10
|
# Shared dependencies for all crates
|
|
11
11
|
[workspace.dependencies]
|
|
12
12
|
magnus = { version = "0.8.2", features = ["rb-sys"] }
|
|
13
13
|
rb-sys = "0.9.128"
|
|
14
|
-
glaz-module = { git = "https://gitlab.com/gitlab-org/auth/glaz.git", rev = "
|
|
14
|
+
glaz-module = { git = "https://gitlab.com/gitlab-org/auth/glaz.git", rev = "13a32ad3f0e6490384afb6ba6a3c3e2a6439901a" }
|
|
15
|
+
glaz-roles = { git = "https://gitlab.com/gitlab-org/auth/glaz.git", rev = "13a32ad3f0e6490384afb6ba6a3c3e2a6439901a" }
|
data/README.md
CHANGED
|
@@ -3,68 +3,52 @@
|
|
|
3
3
|
> [!WARNING]
|
|
4
4
|
> This gem is currently designed entirely for internal use at GitLab.
|
|
5
5
|
|
|
6
|
-
Ruby bindings for the [Glaz](https://gitlab.com/gitlab-org/auth/glaz) authorization engine.
|
|
7
|
-
|
|
8
|
-
## Requirements
|
|
9
|
-
|
|
10
|
-
- Ruby >= 3.1
|
|
11
|
-
- Rust toolchain (for building the native extension)
|
|
6
|
+
Ruby bindings for the [Glaz](https://gitlab.com/gitlab-org/auth/glaz) authorization engine. A thin [Magnus](https://github.com/matsadler/magnus) FFI extension exposes the Rust `glaz-module` engine to Ruby, so Cedar policy checks run in-process.
|
|
12
7
|
|
|
13
8
|
## Installation
|
|
14
9
|
|
|
15
|
-
Add to your Gemfile:
|
|
10
|
+
Requires Ruby >= 3.1 and a Rust toolchain. Add to your Gemfile:
|
|
16
11
|
|
|
17
12
|
```ruby
|
|
18
13
|
gem 'gitlab-glaz', path: 'gems/gitlab-glaz'
|
|
19
14
|
```
|
|
20
15
|
|
|
21
|
-
## Building
|
|
22
|
-
|
|
23
|
-
The gem contains a Rust extension that must be compiled before use:
|
|
24
|
-
|
|
25
|
-
```shell
|
|
26
|
-
bundle exec rake compile
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
This compiles the Rust crate in `ext/glaz/` and places the resulting native library under `lib/glaz/`.
|
|
30
|
-
|
|
31
16
|
## Usage
|
|
32
17
|
|
|
33
18
|
```ruby
|
|
34
19
|
require 'gitlab-glaz'
|
|
35
20
|
|
|
36
|
-
|
|
37
|
-
```
|
|
21
|
+
engine = Gitlab::Glaz::Engine.new(schema: cedar_schema, policies: cedar_policies)
|
|
38
22
|
|
|
39
|
-
|
|
23
|
+
engine.check_action(
|
|
24
|
+
subject_uuid: user_uuid,
|
|
25
|
+
object_uuid: project_uuid,
|
|
26
|
+
action: 'read_docs',
|
|
27
|
+
context: {}
|
|
28
|
+
)
|
|
29
|
+
# => { allowed: true, reason: 'permit_granted' }
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
| Rust extension | `ext/glaz/` | Thin `#[magnus::init]` shim that delegates to `glaz-ruby` |
|
|
46
|
-
| Core engine | [`glaz-ruby`](https://gitlab.com/gitlab-org/auth/glaz) | Rust crate implementing the Glaz authorization engine |
|
|
31
|
+
# Swap the policy set at runtime; the previous set stays active if the
|
|
32
|
+
# new source fails to parse or validate against the schema:
|
|
33
|
+
engine.load_policies(new_cedar_policies)
|
|
34
|
+
```
|
|
47
35
|
|
|
48
|
-
|
|
36
|
+
The schema is loaded once at construction and cannot change; build a new engine to use a new schema.
|
|
49
37
|
|
|
50
|
-
|
|
38
|
+
Schemas must declare `User` and `Resource` entities (checks build `User::"<subject_uuid>"` and `Resource::"<object_uuid>"` UIDs), and every action's context type must include `user_permissions: Set<Action>`, which the engine injects with the checked action.
|
|
51
39
|
|
|
52
|
-
|
|
40
|
+
## Development
|
|
53
41
|
|
|
54
42
|
```shell
|
|
55
|
-
|
|
43
|
+
bundle exec rake compile # build the native extension (required before rspec)
|
|
44
|
+
bundle exec rspec
|
|
56
45
|
```
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```shell
|
|
61
|
-
bundle exec rake
|
|
62
|
-
```
|
|
47
|
+
The extension crate lives in [`ext/glaz/`](ext/glaz/); shared Rust dependencies are declared in the root [`Cargo.toml`](Cargo.toml).
|
|
63
48
|
|
|
64
49
|
## Releasing a new version
|
|
65
50
|
|
|
66
|
-
|
|
67
|
-
Once merged, the new version with precompiled, native gems will automatically be published to RubyGems.
|
|
51
|
+
Create a merge request using the `Release` template and follow its instructions. Once merged, precompiled native gems are published to RubyGems automatically.
|
|
68
52
|
|
|
69
53
|
## License
|
|
70
54
|
|
data/ext/glaz/Cargo.toml
CHANGED
data/ext/glaz/src/lib.rs
CHANGED
|
@@ -1,26 +1,48 @@
|
|
|
1
1
|
use magnus::{Error, Ruby, prelude::*};
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/// Thin 1:1 wrapper around `glaz_module::PermissionCheckEngine`. The engine
|
|
4
|
+
/// starts empty; `load_schema` must be called before `load_policies`, and
|
|
5
|
+
/// `check_action` fails with a RuntimeError until both are loaded.
|
|
6
|
+
#[magnus::wrap(class = "Glaz::PermissionCheckEngine")]
|
|
7
|
+
struct PermissionCheckEngine {
|
|
5
8
|
engine: glaz_module::PermissionCheckEngine,
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
impl
|
|
11
|
+
impl PermissionCheckEngine {
|
|
9
12
|
fn initialize(ruby: &Ruby) -> Result<Self, Error> {
|
|
10
|
-
glaz_module::PermissionCheckEngine::new()
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
let engine = glaz_module::PermissionCheckEngine::new().map_err(|e| map_error(ruby, e))?;
|
|
14
|
+
|
|
15
|
+
Ok(Self { engine })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// Load the Cedar schema. Re-loading a schema drops the active policies,
|
|
19
|
+
/// so callers should load the schema exactly once, before any policies.
|
|
20
|
+
fn load_schema(ruby: &Ruby, rb_self: &Self, schema: String) -> Result<(), Error> {
|
|
21
|
+
rb_self
|
|
22
|
+
.engine
|
|
23
|
+
.load_schema(&schema)
|
|
24
|
+
.map_err(|e| map_error(ruby, e))
|
|
13
25
|
}
|
|
14
26
|
|
|
15
|
-
|
|
27
|
+
/// Replace the active policy set with the given Cedar policy source,
|
|
28
|
+
/// validated against the loaded schema. On error the previous policies
|
|
29
|
+
/// remain active.
|
|
30
|
+
fn load_policies(ruby: &Ruby, rb_self: &Self, policies: String) -> Result<(), Error> {
|
|
31
|
+
rb_self
|
|
32
|
+
.engine
|
|
33
|
+
.load_policies(&policies)
|
|
34
|
+
.map_err(|e| map_error(ruby, e))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fn check_action(
|
|
16
38
|
ruby: &Ruby,
|
|
17
|
-
rb_self: &
|
|
39
|
+
rb_self: &Self,
|
|
18
40
|
proto_bytes: magnus::RString,
|
|
19
41
|
) -> Result<magnus::RHash, Error> {
|
|
20
42
|
let bytes = unsafe { proto_bytes.as_slice() };
|
|
21
43
|
let result = rb_self
|
|
22
44
|
.engine
|
|
23
|
-
.
|
|
45
|
+
.check(bytes)
|
|
24
46
|
.map_err(|e| map_error(ruby, e))?;
|
|
25
47
|
let hash = ruby.hash_new();
|
|
26
48
|
hash.aset(ruby.sym_new("allowed"), result.allowed)?;
|
|
@@ -29,10 +51,30 @@ impl CheckPermission {
|
|
|
29
51
|
}
|
|
30
52
|
}
|
|
31
53
|
|
|
54
|
+
/// Return the default roles embedded in the extension at build time (parsed
|
|
55
|
+
/// from glaz-roles' roles/**/*.yml) as an array of hashes shaped like
|
|
56
|
+
/// `{ id: String, name: String, permissions: [String, ...] }`.
|
|
57
|
+
fn roles(ruby: &Ruby) -> Result<magnus::RArray, Error> {
|
|
58
|
+
let array = ruby.ary_new();
|
|
59
|
+
for role in glaz_roles::default_roles() {
|
|
60
|
+
let hash = ruby.hash_new();
|
|
61
|
+
hash.aset(ruby.sym_new("id"), role.id.to_string())?;
|
|
62
|
+
hash.aset(ruby.sym_new("name"), role.name)?;
|
|
63
|
+
let permissions = ruby.ary_new();
|
|
64
|
+
for permission in &role.permissions {
|
|
65
|
+
permissions.push(permission.as_str())?;
|
|
66
|
+
}
|
|
67
|
+
hash.aset(ruby.sym_new("permissions"), permissions)?;
|
|
68
|
+
array.push(hash)?;
|
|
69
|
+
}
|
|
70
|
+
Ok(array)
|
|
71
|
+
}
|
|
72
|
+
|
|
32
73
|
fn map_error(ruby: &Ruby, e: glaz_module::GlazError) -> Error {
|
|
33
74
|
use glaz_module::GlazError::*;
|
|
34
75
|
match e {
|
|
35
76
|
InvalidArgument(_) => Error::new(ruby.exception_arg_error(), format!("{e}")),
|
|
77
|
+
NotInitialized(_) => Error::new(ruby.exception_runtime_error(), format!("{e}")),
|
|
36
78
|
Runtime(_) => Error::new(ruby.exception_runtime_error(), format!("{e}")),
|
|
37
79
|
}
|
|
38
80
|
}
|
|
@@ -40,12 +82,23 @@ fn map_error(ruby: &Ruby, e: glaz_module::GlazError) -> Error {
|
|
|
40
82
|
#[magnus::init]
|
|
41
83
|
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
42
84
|
let glaz = ruby.define_module("Glaz")?;
|
|
43
|
-
|
|
44
|
-
let class =
|
|
45
|
-
class.define_singleton_method(
|
|
85
|
+
glaz.define_singleton_method("roles", magnus::function!(roles, 0))?;
|
|
86
|
+
let class = glaz.define_class("PermissionCheckEngine", ruby.class_object())?;
|
|
87
|
+
class.define_singleton_method(
|
|
88
|
+
"new",
|
|
89
|
+
magnus::function!(PermissionCheckEngine::initialize, 0),
|
|
90
|
+
)?;
|
|
91
|
+
class.define_method(
|
|
92
|
+
"load_schema",
|
|
93
|
+
magnus::method!(PermissionCheckEngine::load_schema, 1),
|
|
94
|
+
)?;
|
|
95
|
+
class.define_method(
|
|
96
|
+
"load_policies",
|
|
97
|
+
magnus::method!(PermissionCheckEngine::load_policies, 1),
|
|
98
|
+
)?;
|
|
46
99
|
class.define_method(
|
|
47
|
-
"
|
|
48
|
-
magnus::method!(
|
|
100
|
+
"check_action",
|
|
101
|
+
magnus::method!(PermissionCheckEngine::check_action, 1),
|
|
49
102
|
)?;
|
|
50
103
|
Ok(())
|
|
51
104
|
}
|
data/lib/gitlab/glaz/3.1/glaz.so
CHANGED
|
Binary file
|
data/lib/gitlab/glaz/3.2/glaz.so
CHANGED
|
Binary file
|
data/lib/gitlab/glaz/3.3/glaz.so
CHANGED
|
Binary file
|
data/lib/gitlab/glaz/3.4/glaz.so
CHANGED
|
Binary file
|
data/lib/gitlab/glaz/4.0/glaz.so
CHANGED
|
Binary file
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module Glaz
|
|
7
|
+
# Wraps a native Glaz::PermissionCheckEngine instance.
|
|
8
|
+
#
|
|
9
|
+
# The Cedar schema is fixed for the lifetime of the engine: it is loaded
|
|
10
|
+
# exactly once at construction and cannot be re-loaded; build a new Engine
|
|
11
|
+
# to change it. The policy set can be replaced at any time with
|
|
12
|
+
# #load_policies.
|
|
13
|
+
#
|
|
14
|
+
# Schemas must declare `User` and `Resource` entity types and declare
|
|
15
|
+
# each checkable action with `appliesTo { principal: [User], resource:
|
|
16
|
+
# [Resource], ... }`, because the engine builds `User::"<subject_uuid>"` and
|
|
17
|
+
# `Resource::"<object_uuid>"` entity UIDs for every check. The engine also
|
|
18
|
+
# injects `user_permissions` (a Set<Action> containing the checked action)
|
|
19
|
+
# into the Cedar context, so an action's declared context type must include
|
|
20
|
+
# `user_permissions: Set<Action>` alongside any custom attributes.
|
|
21
|
+
class Engine
|
|
22
|
+
# @param schema [String] Cedar schema source (`.cedarschema` DSL).
|
|
23
|
+
# @param policies [String] Cedar policy source, validated against the
|
|
24
|
+
# schema; ArgumentError is raised when either does not parse or the
|
|
25
|
+
# policies do not validate.
|
|
26
|
+
def initialize(schema:, policies:)
|
|
27
|
+
@native = ::Glaz::PermissionCheckEngine.new
|
|
28
|
+
@native.load_schema(schema)
|
|
29
|
+
@native.load_policies(policies)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Replace the active policy set with the given Cedar policy source,
|
|
33
|
+
# validated against the engine's schema. Raises ArgumentError when the
|
|
34
|
+
# source does not parse or validate; the previous policies then remain
|
|
35
|
+
# active. The swap is atomic with respect to concurrent checks.
|
|
36
|
+
def load_policies(source)
|
|
37
|
+
@native.load_policies(source)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Evaluate whether the subject may perform +action+ on the object.
|
|
41
|
+
#
|
|
42
|
+
# @param context [Hash] ABAC attributes made available to policies as the
|
|
43
|
+
# Cedar context; must match the context type the schema declares for
|
|
44
|
+
# the checked action.
|
|
45
|
+
# @return [Hash] { allowed: Boolean, reason: String }
|
|
46
|
+
def check_action(subject_uuid:, object_uuid:, action:, context: {})
|
|
47
|
+
request = ::Glaz::CheckRequest.encode(
|
|
48
|
+
::Glaz::CheckRequest.new(
|
|
49
|
+
subject: ::Relationships::V1::Principal.new(id: subject_uuid),
|
|
50
|
+
action: action,
|
|
51
|
+
object: ::Relationships::V1::Object.new(id: object_uuid),
|
|
52
|
+
context: context.to_json
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
@native.check_action(request)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/gitlab/glaz/version.rb
CHANGED
data/lib/gitlab/glaz.rb
CHANGED
|
@@ -6,21 +6,20 @@ require "proto/service_pb"
|
|
|
6
6
|
|
|
7
7
|
load_rust_extension
|
|
8
8
|
|
|
9
|
+
require_relative "glaz/engine"
|
|
10
|
+
|
|
9
11
|
module Gitlab
|
|
10
12
|
module Glaz
|
|
11
13
|
module_function
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
::Glaz::Engine::CheckPermission.new.check_permission(request)
|
|
15
|
+
# Returns the default roles embedded in the native extension at build time,
|
|
16
|
+
# sourced from the glaz-roles crate's roles/**/*.yml definitions. Each entry
|
|
17
|
+
# is a hash: { id: String, name: String, permissions: Array<String> }.
|
|
18
|
+
def roles
|
|
19
|
+
@roles ||= ::Glaz.roles.each do |role|
|
|
20
|
+
role[:permissions].freeze
|
|
21
|
+
role.freeze
|
|
22
|
+
end.freeze
|
|
24
23
|
end
|
|
25
24
|
end
|
|
26
25
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# source: proto/relationships/relationships.proto
|
|
4
|
+
|
|
5
|
+
require 'google/protobuf'
|
|
6
|
+
|
|
7
|
+
require 'google/protobuf/timestamp_pb'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
descriptor_data = "\n\'proto/relationships/relationships.proto\x12\x10relationships.v1\x1a\x1fgoogle/protobuf/timestamp.proto\"\x14\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\t\"\x17\n\tPrincipal\x12\n\n\x02id\x18\x01 \x01(\t\"\x12\n\x04Role\x12\n\n\x02id\x18\x01 \x01(\t\"Y\n\x08Identity\x12(\n\x06origin\x18\x01 \x01(\x0e\x32\x18.relationships.v1.Origin\x12\x11\n\torigin_id\x18\x02 \x01(\t\x12\x10\n\x08local_id\x18\x03 \x01(\t\"q\n\x07Subject\x12.\n\x08identity\x18\x01 \x01(\x0b\x32\x1a.relationships.v1.IdentityH\x00\x12\x30\n\tprincipal\x18\x02 \x01(\x0b\x32\x1b.relationships.v1.PrincipalH\x00\x42\x04\n\x02id\"\xdf\x01\n\x0cRelationship\x12*\n\x07subject\x18\x01 \x01(\x0b\x32\x19.relationships.v1.Subject\x12(\n\x06object\x18\x02 \x01(\x0b\x32\x18.relationships.v1.Object\x12$\n\x04kind\x18\x03 \x01(\x0e\x32\x16.relationships.v1.Kind\x12$\n\x04role\x18\x04 \x01(\x0b\x32\x16.relationships.v1.Role\x12-\n\ttimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xb5\x01\n\x11RelationshipInput\x12*\n\x07subject\x18\x01 \x01(\x0b\x32\x19.relationships.v1.Subject\x12(\n\x06object\x18\x02 \x01(\x0b\x32\x18.relationships.v1.Object\x12$\n\x04kind\x18\x03 \x01(\x0e\x32\x16.relationships.v1.Kind\x12$\n\x04role\x18\x04 \x01(\x0b\x32\x16.relationships.v1.Role\"\x8d\x01\n\x0fRelationshipKey\x12*\n\x07subject\x18\x01 \x01(\x0b\x32\x19.relationships.v1.Subject\x12(\n\x06object\x18\x02 \x01(\x0b\x32\x18.relationships.v1.Object\x12$\n\x04kind\x18\x03 \x01(\x0e\x32\x16.relationships.v1.Kind*1\n\x04Kind\x12\x14\n\x10KIND_UNSPECIFIED\x10\x00\x12\x13\n\x0fKIND_ASSIGNMENT\x10\x01*N\n\x06Origin\x12\x16\n\x12ORIGIN_UNSPECIFIED\x10\x00\x12\x0f\n\x0bORIGIN_SELF\x10\x01\x12\x1b\n\x17ORIGIN_GITLAB_FEDERATED\x10\x02\x42\x34Z2gitlab.com/gitlab-org/auth/iam/proto/relationshipsb\x06proto3"
|
|
11
|
+
|
|
12
|
+
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
|
13
|
+
pool.add_serialized_file(descriptor_data)
|
|
14
|
+
|
|
15
|
+
module Relationships
|
|
16
|
+
module V1
|
|
17
|
+
Object = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Object").msgclass
|
|
18
|
+
Principal = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Principal").msgclass
|
|
19
|
+
Role = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Role").msgclass
|
|
20
|
+
Identity = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Identity").msgclass
|
|
21
|
+
Subject = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Subject").msgclass
|
|
22
|
+
Relationship = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Relationship").msgclass
|
|
23
|
+
RelationshipInput = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.RelationshipInput").msgclass
|
|
24
|
+
RelationshipKey = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.RelationshipKey").msgclass
|
|
25
|
+
Kind = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Kind").enummodule
|
|
26
|
+
Origin = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("relationships.v1.Origin").enummodule
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/proto/service_pb.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
2
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
4
|
-
# source: service.proto
|
|
3
|
+
# source: proto/service.proto
|
|
5
4
|
|
|
6
5
|
require 'google/protobuf'
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
require 'proto/relationships/relationships_pb'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
descriptor_data = "\n\x13proto/service.proto\x12\x04glaz\x1a\'proto/relationships/relationships.proto\"?\n\x0e\x45xplainRequest\x12\x0f\n\x07subject\x18\x01 \x01(\t\x12\x0e\n\x06object\x18\x02 \x01(\t\x12\x0c\n\x04role\x18\x03 \x01(\x05\"2\n\x0f\x45xplainResponse\x12\x0f\n\x07\x61llowed\x18\x01 \x01(\x08\x12\x0e\n\x06reason\x18\x02 \x01(\t\"2\n\x0f\x45valuateRequest\x12\x0f\n\x07subject\x18\x01 \x01(\t\x12\x0e\n\x06object\x18\x02 \x01(\t\"3\n\x10\x45valuateResponse\x12\x0f\n\x07\x61llowed\x18\x01 \x01(\x08\x12\x0e\n\x06reason\x18\x02 \x01(\t\"\xbe\x01\n\x0c\x43heckRequest\x12,\n\x07subject\x18\x01 \x01(\x0b\x32\x1b.relationships.v1.Principal\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12(\n\x06object\x18\x03 \x01(\x0b\x32\x18.relationships.v1.Object\x12\x35\n\rrelationships\x18\x04 \x03(\x0b\x32\x1e.relationships.v1.Relationship\x12\x0f\n\x07\x63ontext\x18\x05 \x01(\t\"0\n\rCheckResponse\x12\x0f\n\x07\x61llowed\x18\x01 \x01(\x08\x12\x0e\n\x06reason\x18\x02 \x01(\t2\xbb\x01\n\x14\x41uthorizationService\x12\x36\n\x07\x45xplain\x12\x14.glaz.ExplainRequest\x1a\x15.glaz.ExplainResponse\x12\x39\n\x08\x45valuate\x12\x15.glaz.EvaluateRequest\x1a\x16.glaz.EvaluateResponse\x12\x30\n\x05\x43heck\x12\x12.glaz.CheckRequest\x1a\x13.glaz.CheckResponseb\x06proto3"
|
|
9
11
|
|
|
10
12
|
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
|
11
13
|
pool.add_serialized_file(descriptor_data)
|
|
@@ -15,6 +17,6 @@ module Glaz
|
|
|
15
17
|
ExplainResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.ExplainResponse").msgclass
|
|
16
18
|
EvaluateRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.EvaluateRequest").msgclass
|
|
17
19
|
EvaluateResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.EvaluateResponse").msgclass
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
CheckRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.CheckRequest").msgclass
|
|
21
|
+
CheckResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.CheckResponse").msgclass
|
|
20
22
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-glaz
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: x86_64-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- group::authorization
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: google-protobuf
|
|
@@ -101,8 +101,10 @@ files:
|
|
|
101
101
|
- lib/gitlab/glaz/3.3/glaz.so
|
|
102
102
|
- lib/gitlab/glaz/3.4/glaz.so
|
|
103
103
|
- lib/gitlab/glaz/4.0/glaz.so
|
|
104
|
+
- lib/gitlab/glaz/engine.rb
|
|
104
105
|
- lib/gitlab/glaz/loader.rb
|
|
105
106
|
- lib/gitlab/glaz/version.rb
|
|
107
|
+
- lib/proto/relationships/relationships_pb.rb
|
|
106
108
|
- lib/proto/service_pb.rb
|
|
107
109
|
homepage: https://gitlab.com/gitlab-org/ruby/gems/gitlab-glaz
|
|
108
110
|
licenses:
|