Define gRPC Check contract for AR ↔️ GLAZ
What
Defines the gRPC Check contract for the Artifact Registry
Closes part of gitlab-org/gitlab#602709. Per proposal 014, the host pre-assembles all decision inputs and GLAZ is pure Cedar compute over those inputs.
Contract
CheckRequest (one subject, one action, one resource):
relationships.v1.Principal subject— typed asPrincipal(not theSubjectoneof) to encode "always a principal UUID"; identity resolution happens upstream in the host.string action— e.g.read_repository(named "action", not "permission").relationships.v1.Object objectrepeated relationships.v1.Relationship relationships— assignment records the host fetched, filtered to the object and its ancestors.string context—~~ ABAC attributes, mirroring GLAZ's internalHashMap<String, serde_json::Value>.~~
Explain / Evaluate are unchanged. The batched entry point is a
deferred follow-up.
Example Check call
A concrete request showing how both RBAC (relationships) and ABAC
(context) inputs are supplied. Scenario: may this principal
read_repository on a private repository, given it holds a role on the
repository's parent namespace?
CheckRequest (proto3 JSON):
{
"subject": { "id": "0190c8e2-7f3a-7b1c-8a2d-1f2e3d4c5b6a" },
"action": "read_repository",
"object": { "id": "0190c8e2-8a01-7c4d-9b3e-2a3b4c5d6e7f" },
"relationships": [
{
"subject": { "principal": { "id": "0190c8e2-7f3a-7b1c-8a2d-1f2e3d4c5b6a" } },
"object": { "id": "0190c8e2-9b12-7d5e-8c4f-3b4c5d6e7f80" },
"kind": "KIND_ASSIGNMENT",
"role": { "id": "0190c8e2-aa23-7e6f-9d50-4c5d6e7f8091" }
}
],
"context": {
"repository": {
"quarantined": true
}
}
}subject/action/object— the principal, the action, and the repository being checked.relationships(RBAC) — the assignment tuples the host pre-fetched, filtered to the object and its ancestors. Here the principal holds role…8091(e.g. Artifact Viewer) on the repository's parent namespace…7f80;subject.principalis set, since identities are resolved upstream. GLAZ derives the effective permission set from these grants.context(ABAC) — resource attributes as a JSON object; this is how runtime policies receive their inputs. A Cedar policy can branch oncontext.visibility,context.type, etc. (e.g. tightening access onprivaterepositories).
CheckResponse:
{ "allowed": true, "reason": "permit_role_granted" }Over the wire with grpcurl (request.json holds the CheckRequest above):
grpcurl -plaintext -d @ localhost:50051 glaz.AuthorizationService/Check < request.jsonThe response is illustrative: it shows the decision shape, not a result produced on this branch — policy evaluation lands with the engine work (see follow-ups).
Vendored protos (interim sharing mechanism)
| File | Source | Ref |
|---|---|---|
proto/relationships/relationships.proto |
gitlab-org/auth/iam | main @ fc026c3 |
buf/validate/validate.proto |
bufbuild/protovalidate | v1.2.0 |
validate.proto matches the protovalidate version iam pins in its
buf.lock / go.mod. proto/README.md records provenance so drift is
auditable. A sync script / drift-detection CI check is a noted follow-up.
Build wiring
- Both crates switch from single-package
include!/include_proto!to prost's.include_file(...)so cross-package references resolve. - Added
prost-typesfor the well-known types (Struct,Timestamp). extern_path(".buf.validate", "()")suppresses codegen for thebuf.validatemessages — they're only referenced as proto options (which prost drops) and otherwise trip clippy'slen_without_is_emptyunder CI's-D warnings.glaz-module(an existingCheckRequestconsumer) is adapted to the new shape so the workspace keeps building.⚠️ Not in the original task's file list — flagging for reviewers.
Verification
cargo build --workspace --locked✅ cargo clippy --workspace --locked -- -D warnings✅ cargo test --workspace --locked✅
Follow-ups (out of scope)
- Batched
Check(one subject, many action/resource pairs). - Permanent proto-sharing (submodule / BSR / extracted repo) + drift CI.
- Per-ancestor resource attributes if Cedar policies need them.
- Server implementation / type translation / engine logic.