aboutsummaryrefslogtreecommitdiff
path: root/crates/secd/proto/authzed/api
diff options
context:
space:
mode:
Diffstat (limited to 'crates/secd/proto/authzed/api')
-rw-r--r--crates/secd/proto/authzed/api/v0/core.proto58
-rw-r--r--crates/secd/proto/authzed/api/v0/developer.proto135
-rw-r--r--crates/secd/proto/authzed/api/v1/core.proto145
-rw-r--r--crates/secd/proto/authzed/api/v1/debug.proto103
-rw-r--r--crates/secd/proto/authzed/api/v1/error_reason.proto197
-rw-r--r--crates/secd/proto/authzed/api/v1/openapi.proto43
-rw-r--r--crates/secd/proto/authzed/api/v1/permission_service.proto438
-rw-r--r--crates/secd/proto/authzed/api/v1/schema_service.proto53
-rw-r--r--crates/secd/proto/authzed/api/v1/watch_service.proto44
-rw-r--r--crates/secd/proto/authzed/api/v1alpha1/schema.proto68
-rw-r--r--crates/secd/proto/authzed/api/v1alpha1/watchresources_service.proto83
11 files changed, 1367 insertions, 0 deletions
diff --git a/crates/secd/proto/authzed/api/v0/core.proto b/crates/secd/proto/authzed/api/v0/core.proto
new file mode 100644
index 0000000..d42eb04
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v0/core.proto
@@ -0,0 +1,58 @@
+syntax = "proto3";
+package authzed.api.v0;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v0";
+option java_package = "com.authzed.api.v0";
+
+import "validate/validate.proto";
+
+message RelationTuple {
+ // Each tupleset specifies keys of a set of relation tuples. The set can
+ // include a single tuple key, or all tuples with a given object ID or
+ // userset in a namespace, optionally constrained by a relation name.
+ //
+ // examples:
+ // doc:readme#viewer@group:eng#member (fully specified)
+ // doc:*#*#group:eng#member (all tuples that this userset relates to)
+ // doc:12345#*#* (all tuples with a direct relationship to a document)
+ // doc:12345#writer#* (all tuples with direct write relationship with the
+ // document) doc:#writer#group:eng#member (all tuples that eng group has write
+ // relationship)
+ ObjectAndRelation object_and_relation = 1
+ [ (validate.rules).message.required = true ];
+ User user = 2 [ (validate.rules).message.required = true ];
+}
+
+message ObjectAndRelation {
+ string namespace = 1 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+ string object_id = 2 [ (validate.rules).string = {
+ pattern : "^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)$",
+ max_bytes : 128,
+ } ];
+ string relation = 3 [ (validate.rules).string = {
+ pattern : "^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$",
+ max_bytes : 64,
+ } ];
+}
+
+message RelationReference {
+ string namespace = 1 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+ string relation = 3 [ (validate.rules).string = {
+ pattern : "^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$",
+ max_bytes : 64,
+ } ];
+}
+
+message User {
+ oneof user_oneof {
+ option (validate.required) = true;
+
+ ObjectAndRelation userset = 2 [ (validate.rules).message.required = true ];
+ }
+}
diff --git a/crates/secd/proto/authzed/api/v0/developer.proto b/crates/secd/proto/authzed/api/v0/developer.proto
new file mode 100644
index 0000000..9a4b97d
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v0/developer.proto
@@ -0,0 +1,135 @@
+syntax = "proto3";
+package authzed.api.v0;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v0";
+option java_package = "com.authzed.api.v0";
+
+import "authzed/api/v0/core.proto";
+
+service DeveloperService {
+ rpc EditCheck(EditCheckRequest) returns (EditCheckResponse) {}
+ rpc Validate(ValidateRequest) returns (ValidateResponse) {}
+ rpc Share(ShareRequest) returns (ShareResponse) {}
+ rpc LookupShared(LookupShareRequest) returns (LookupShareResponse) {}
+ rpc UpgradeSchema(UpgradeSchemaRequest) returns (UpgradeSchemaResponse) {}
+ rpc FormatSchema(FormatSchemaRequest) returns (FormatSchemaResponse) {}
+}
+
+message FormatSchemaRequest {
+ string schema = 1;
+}
+
+message FormatSchemaResponse {
+ DeveloperError error = 1;
+ string formatted_schema = 2;
+}
+
+message UpgradeSchemaRequest {
+ repeated string namespace_configs = 1;
+}
+
+message UpgradeSchemaResponse {
+ DeveloperError error = 1;
+ string upgraded_schema = 2;
+}
+
+message ShareRequest {
+ string schema = 1;
+ string relationships_yaml = 2;
+ string validation_yaml = 3;
+ string assertions_yaml = 4;
+}
+
+message ShareResponse {
+ string share_reference = 1;
+}
+
+message LookupShareRequest {
+ string share_reference = 1;
+}
+
+message LookupShareResponse {
+ enum LookupStatus {
+ UNKNOWN_REFERENCE = 0;
+ FAILED_TO_LOOKUP = 1;
+ VALID_REFERENCE = 2;
+ UPGRADED_REFERENCE = 3;
+ }
+
+ LookupStatus status = 1;
+ string schema = 2;
+ string relationships_yaml = 3;
+ string validation_yaml = 4;
+ string assertions_yaml = 5;
+}
+
+message RequestContext {
+ string schema = 1;
+ repeated RelationTuple relationships = 2;
+ reserved 3; // Was legacy_ns_configs
+}
+
+message EditCheckRequest {
+ RequestContext context = 1;
+ repeated RelationTuple check_relationships = 2;
+}
+
+message EditCheckResult {
+ RelationTuple relationship = 1;
+ bool is_member = 2;
+ DeveloperError error = 3;
+}
+
+message EditCheckResponse {
+ repeated DeveloperError request_errors = 1;
+ repeated EditCheckResult check_results = 2;
+}
+
+message ValidateRequest {
+ RequestContext context = 1;
+ string validation_yaml = 3;
+ bool update_validation_yaml = 4;
+ string assertions_yaml = 5;
+}
+
+message ValidateResponse {
+ repeated DeveloperError request_errors = 1;
+ repeated DeveloperError validation_errors = 2;
+ string updated_validation_yaml = 3;
+}
+
+message DeveloperError {
+ enum Source {
+ UNKNOWN_SOURCE = 0;
+ SCHEMA = 1;
+ RELATIONSHIP = 2;
+ VALIDATION_YAML = 3;
+ CHECK_WATCH = 4;
+ ASSERTION = 5;
+ }
+
+ enum ErrorKind {
+ UNKNOWN_KIND = 0;
+ PARSE_ERROR = 1;
+ SCHEMA_ISSUE = 2;
+ DUPLICATE_RELATIONSHIP = 3;
+ MISSING_EXPECTED_RELATIONSHIP = 4;
+ EXTRA_RELATIONSHIP_FOUND = 5;
+ UNKNOWN_OBJECT_TYPE = 6;
+ UNKNOWN_RELATION = 7;
+ MAXIMUM_RECURSION = 8;
+ ASSERTION_FAILED = 9;
+ }
+
+ string message = 1;
+ uint32 line = 2;
+ uint32 column = 3;
+ Source source = 4;
+ ErrorKind kind = 5;
+
+ repeated string path = 6;
+
+ // context holds the context for the error. For schema issues, this will be the
+ // name of the object type. For relationship issues, the full relationship string.
+ string context = 7;
+}
diff --git a/crates/secd/proto/authzed/api/v1/core.proto b/crates/secd/proto/authzed/api/v1/core.proto
new file mode 100644
index 0000000..25bf78b
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1/core.proto
@@ -0,0 +1,145 @@
+syntax = "proto3";
+package authzed.api.v1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
+option java_package = "com.authzed.api.v1";
+
+import "google/protobuf/struct.proto";
+import "validate/validate.proto";
+
+// Relationship specifies how a resource relates to a subject. Relationships
+// form the data for the graph over which all permissions questions are
+// answered.
+message Relationship {
+ // resource is the resource to which the subject is related, in some manner
+ ObjectReference resource = 1 [ (validate.rules).message.required = true ];
+
+ // relation is how the resource and subject are related.
+ string relation = 2 [ (validate.rules).string = {
+ pattern : "^[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 64,
+ } ];
+
+ // subject is the subject to which the resource is related, in some manner.
+ SubjectReference subject = 3 [ (validate.rules).message.required = true ];
+
+ // optional_caveat is a reference to a the caveat that must be enforced over the relationship
+ ContextualizedCaveat optional_caveat = 4 [ (validate.rules).message.required = false ];
+}
+
+/**
+ * ContextualizedCaveat represents a reference to a caveat to be used by caveated relationships.
+ * The context consists of key-value pairs that will be injected at evaluation time.
+ * The keys must match the arguments defined on the caveat in the schema.
+ */
+message ContextualizedCaveat {
+ /** caveat_name is the name of the caveat expression to use, as defined in the schema **/
+ string caveat_name = 1 [ (validate.rules).string = {
+ pattern : "^([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})$",
+ max_bytes : 128,
+ } ];
+
+ /** context consists of any named values that are defined at write time for the caveat expression **/
+ google.protobuf.Struct context = 2 [ (validate.rules).message.required = false ];
+}
+
+// SubjectReference is used for referring to the subject portion of a
+// Relationship. The relation component is optional and is used for defining a
+// sub-relation on the subject, e.g. group:123#members
+message SubjectReference {
+ ObjectReference object = 1 [ (validate.rules).message.required = true ];
+ string optional_relation = 2 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
+ max_bytes : 64,
+ } ];
+}
+
+// ObjectReference is used to refer to a specific object in the system.
+message ObjectReference {
+ string object_type = 1 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+ string object_id = 2 [ (validate.rules).string = {
+ pattern : "^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)$",
+ max_bytes : 128,
+ } ];
+}
+
+// ZedToken is used to provide causality metadata between Write and Check
+// requests.
+//
+// See the authzed.api.v1.Consistency message for more information.
+message ZedToken {
+ string token = 1 [ (validate.rules).string = {
+ min_bytes : 1,
+ } ];
+}
+
+// RelationshipUpdate is used for mutating a single relationship within the
+// service.
+//
+// CREATE will create the relationship only if it doesn't exist, and error
+// otherwise.
+//
+// TOUCH will upsert the relationship, and will not error if it
+// already exists.
+//
+// DELETE will delete the relationship and error if it doesn't
+// exist.
+message RelationshipUpdate {
+ enum Operation {
+ OPERATION_UNSPECIFIED = 0;
+ OPERATION_CREATE = 1;
+ OPERATION_TOUCH = 2;
+ OPERATION_DELETE = 3;
+ }
+ Operation operation = 1 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+ Relationship relationship = 2 [ (validate.rules).message.required = true ];
+}
+
+// PermissionRelationshipTree is used for representing a tree of a resource and
+// its permission relationships with other objects.
+message PermissionRelationshipTree {
+ oneof tree_type {
+ option (validate.required) = true;
+
+ AlgebraicSubjectSet intermediate = 1;
+ DirectSubjectSet leaf = 2;
+ }
+ ObjectReference expanded_object = 3;
+ string expanded_relation = 4;
+}
+
+// AlgebraicSubjectSet is a subject set which is computed based on applying the
+// specified operation to the operands according to the algebra of sets.
+//
+// UNION is a logical set containing the subject members from all operands.
+//
+// INTERSECTION is a logical set containing only the subject members which are
+// present in all operands.
+//
+// EXCLUSION is a logical set containing only the subject members which are
+// present in the first operand, and none of the other operands.
+message AlgebraicSubjectSet {
+ enum Operation {
+ OPERATION_UNSPECIFIED = 0;
+ OPERATION_UNION = 1;
+ OPERATION_INTERSECTION = 2;
+ OPERATION_EXCLUSION = 3;
+ }
+
+ Operation operation = 1 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+ repeated PermissionRelationshipTree children = 2 [ (validate.rules).repeated.items.message.required = true ];
+}
+
+// DirectSubjectSet is a subject set which is simply a collection of subjects.
+message DirectSubjectSet { repeated SubjectReference subjects = 1; }
+
+// PartialCaveatInfo carries information necessary for the client to take action
+// in the event a response contains a partially evaluated caveat
+message PartialCaveatInfo {
+ // missing_required_context is a list of one or more fields that were missing and prevented caveats
+ // from being fully evaluated
+ repeated string missing_required_context = 1 [(validate.rules).repeated.min_items = 1];
+}
diff --git a/crates/secd/proto/authzed/api/v1/debug.proto b/crates/secd/proto/authzed/api/v1/debug.proto
new file mode 100644
index 0000000..f02fa82
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1/debug.proto
@@ -0,0 +1,103 @@
+syntax = "proto3";
+package authzed.api.v1;
+
+import "authzed/api/v1/core.proto";
+import "validate/validate.proto";
+import "google/protobuf/struct.proto";
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
+option java_package = "com.authzed.api.v1";
+
+// DebugInformation defines debug information returned by an API call in a footer when
+// requested with a specific debugging header.
+//
+// The specific debug information returned will depend on the type of the API call made.
+//
+// See the github.com/authzed/authzed-go project for the specific header and footer names.
+message DebugInformation {
+ // check holds debug information about a check request.
+ CheckDebugTrace check = 1;
+
+ // schema_used holds the schema used for the request.
+ string schema_used = 2;
+}
+
+// CheckDebugTrace is a recursive trace of the requests made for resolving a CheckPermission
+// API call.
+message CheckDebugTrace {
+ enum PermissionType {
+ PERMISSION_TYPE_UNSPECIFIED = 0;
+ PERMISSION_TYPE_RELATION = 1;
+ PERMISSION_TYPE_PERMISSION = 2;
+ }
+
+ enum Permissionship {
+ PERMISSIONSHIP_UNSPECIFIED = 0;
+ PERMISSIONSHIP_NO_PERMISSION = 1;
+ PERMISSIONSHIP_HAS_PERMISSION = 2;
+ PERMISSIONSHIP_CONDITIONAL_PERMISSION = 3;
+ }
+
+ message SubProblems {
+ repeated CheckDebugTrace traces = 1;
+ }
+
+ // resource holds the resource on which the Check was performed.
+ ObjectReference resource = 1 [ (validate.rules).message.required = true ];
+
+ // permission holds the name of the permission or relation on which the Check was performed.
+ string permission = 2;
+
+ // permission_type holds information indicating whether it was a permission or relation.
+ PermissionType permission_type = 3 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+
+ // subject holds the subject on which the Check was performed. This will be static across all calls within
+ // the same Check tree.
+ SubjectReference subject = 4 [ (validate.rules).message.required = true ];
+
+ // result holds the result of the Check call.
+ Permissionship result = 5 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+
+ // caveat_evaluation_info holds information about the caveat evaluated for this step of the trace.
+ CaveatEvalInfo caveat_evaluation_info = 8;
+
+ // resolution holds information about how the problem was resolved.
+ oneof resolution {
+ option (validate.required) = true;
+
+ // was_cached_result, if true, indicates that the result was found in the cache and returned directly.
+ bool was_cached_result = 6;
+
+ // sub_problems holds the sub problems that were executed to resolve the answer to this Check. An empty list
+ // and a permissionship of PERMISSIONSHIP_HAS_PERMISSION indicates the subject was found within this relation.
+ SubProblems sub_problems = 7;
+ }
+}
+
+// CaveatEvalInfo holds information about a caveat expression that was evaluated.
+message CaveatEvalInfo {
+ enum Result {
+ RESULT_UNSPECIFIED = 0;
+
+ RESULT_UNEVALUATED = 1;
+
+ RESULT_FALSE = 2;
+ RESULT_TRUE = 3;
+ RESULT_MISSING_SOME_CONTEXT = 4;
+ }
+
+ // expression is the expression that was evaluated.
+ string expression = 1;
+
+ // result is the result of the evaluation.
+ Result result = 2;
+
+ // context consists of any named values that were used for evaluating the caveat expression.
+ google.protobuf.Struct context = 3;
+
+ // partial_caveat_info holds information of a partially-evaluated caveated response, if applicable.
+ PartialCaveatInfo partial_caveat_info = 4;
+
+ // caveat_name is the name of the caveat that was executed, if applicable.
+ string caveat_name = 5;
+} \ No newline at end of file
diff --git a/crates/secd/proto/authzed/api/v1/error_reason.proto b/crates/secd/proto/authzed/api/v1/error_reason.proto
new file mode 100644
index 0000000..401a3d0
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1/error_reason.proto
@@ -0,0 +1,197 @@
+syntax = "proto3";
+package authzed.api.v1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
+option java_package = "com.authzed.api.v1";
+
+// Defines the supported values for `google.rpc.ErrorInfo.reason` for the
+// `authzed.com` error domain.
+enum ErrorReason {
+ // Do not use this default value.
+ ERROR_REASON_UNSPECIFIED = 0;
+
+ // The request gave a schema that could not be parsed.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_SCHEMA_PARSE_ERROR",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "start_line_number": "1",
+ // "start_column_position": "19",
+ // "end_line_number": "1",
+ // "end_column_position": "19",
+ // "source_code": "somedefinition",
+ // }
+ // }
+ //
+ // The line numbers and column positions are 0-indexed and may not be present.
+ ERROR_REASON_SCHEMA_PARSE_ERROR = 1;
+
+ // The request contains a schema with a type error.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_SCHEMA_TYPE_ERROR",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "definition_name": "somedefinition",
+ // ... additional keys based on the kind of type error ...
+ // }
+ // }
+ ERROR_REASON_SCHEMA_TYPE_ERROR = 2;
+
+ // The request referenced an unknown object definition in the schema.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_UNKNOWN_DEFINITION",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "definition_name": "somedefinition"
+ // }
+ // }
+ ERROR_REASON_UNKNOWN_DEFINITION = 3;
+
+ // The request referenced an unknown relation or permission under a definition in the schema.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_UNKNOWN_RELATION_OR_PERMISSION",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "definition_name": "somedefinition",
+ // "relation_or_permission_name": "somepermission"
+ // }
+ // }
+ ERROR_REASON_UNKNOWN_RELATION_OR_PERMISSION = 4;
+
+ // The WriteRelationships request contained more updates than the maximum configured.
+ //
+ // Example of an ErrorInfo:
+ //
+ // { "reason": "ERROR_REASON_TOO_MANY_UPDATES_IN_REQUEST",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "update_count": "525",
+ // "maximum_updates_allowed": "500",
+ // }
+ // }
+ ERROR_REASON_TOO_MANY_UPDATES_IN_REQUEST = 5;
+
+ // The request contained more preconditions than the maximum configured.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_TOO_MANY_PRECONDITIONS_IN_REQUEST",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "precondition_count": "525",
+ // "maximum_preconditions_allowed": "500",
+ // }
+ // }
+ ERROR_REASON_TOO_MANY_PRECONDITIONS_IN_REQUEST = 6;
+
+ // The request contained a precondition that failed.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_WRITE_OR_DELETE_PRECONDITION_FAILURE",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "precondition_resource_type": "document",
+ // ... other fields for the filter ...
+ // "precondition_operation": "MUST_EXIST",
+ // }
+ // }
+ ERROR_REASON_WRITE_OR_DELETE_PRECONDITION_FAILURE = 7;
+
+ // A write or delete request was made to an instance that is deployed in read-only mode.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_SERVICE_READ_ONLY",
+ // "domain": "authzed.com"
+ // }
+ ERROR_REASON_SERVICE_READ_ONLY = 8;
+
+ // The request referenced an unknown caveat in the schema.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_UNKNOWN_CAVEAT",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "caveat_name": "somecaveat"
+ // }
+ // }
+ ERROR_REASON_UNKNOWN_CAVEAT = 9;
+
+ // The request tries to use a subject type that was not valid for a relation.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_INVALID_SUBJECT_TYPE",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "definition_name": "somedefinition",
+ // "relation_name": "somerelation",
+ // "subject_type": "user:*"
+ // }
+ // }
+ ERROR_REASON_INVALID_SUBJECT_TYPE = 10;
+
+ // The request tries to specify a caveat parameter value with the wrong type.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_CAVEAT_PARAMETER_TYPE_ERROR",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "definition_name": "somedefinition",
+ // "relation_name": "somerelation",
+ // "caveat_name": "somecaveat",
+ // "parameter_name": "someparameter",
+ // "expected_type": "int",
+ // }
+ // }
+ ERROR_REASON_CAVEAT_PARAMETER_TYPE_ERROR = 11;
+
+ // The request tries to perform two or more updates on the same relationship in the same WriteRelationships call.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_UPDATES_ON_SAME_RELATIONSHIP",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "definition_name": "somedefinition",
+ // "relationship": "somerelationship",
+ // }
+ // }
+ ERROR_REASON_UPDATES_ON_SAME_RELATIONSHIP = 12;
+
+ // The request tries to write a relationship on a permission instead of a relation.
+ //
+ // Example of an ErrorInfo:
+ //
+ // {
+ // "reason": "ERROR_REASON_CANNOT_UPDATE_PERMISSION",
+ // "domain": "authzed.com",
+ // "metadata": {
+ // "definition_name": "somedefinition",
+ // "permission_name": "somerelation",
+ // }
+ // }
+ ERROR_REASON_CANNOT_UPDATE_PERMISSION = 13;
+} \ No newline at end of file
diff --git a/crates/secd/proto/authzed/api/v1/openapi.proto b/crates/secd/proto/authzed/api/v1/openapi.proto
new file mode 100644
index 0000000..693f52a
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1/openapi.proto
@@ -0,0 +1,43 @@
+syntax = "proto3";
+package authzed.api.v1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
+option java_package = "com.authzed.api.v1";
+
+import "protoc-gen-openapiv2/options/annotations.proto";
+
+option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+ info: {
+ title: "Authzed";
+ version: "1.0";
+ contact: {
+ name: "Authzed, Inc.";
+ url: "https://github.com/authzed/api";
+ email: "support@authzed.com";
+ };
+ license: {
+ name: "Apache 2.0 License";
+ url: "https://github.com/authzed/api/blob/main/LICENSE";
+ };
+ };
+ external_docs: {
+ url: "https://docs.authzed.com/reference/api";
+ description: "More about the Authzed API.";
+ }
+ schemes: HTTP;
+ schemes: HTTPS;
+ schemes: WSS;
+ consumes: "application/json";
+ produces: "application/json";
+ security_definitions: {
+ security: {
+ key: "ApiKeyAuth";
+ value: {
+ type: TYPE_API_KEY;
+ in: IN_HEADER;
+ name: "Authorization";
+ }
+ }
+ }
+};
+
diff --git a/crates/secd/proto/authzed/api/v1/permission_service.proto b/crates/secd/proto/authzed/api/v1/permission_service.proto
new file mode 100644
index 0000000..859d0d0
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1/permission_service.proto
@@ -0,0 +1,438 @@
+syntax = "proto3";
+package authzed.api.v1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
+option java_package = "com.authzed.api.v1";
+
+import "google/protobuf/struct.proto";
+import "google/api/annotations.proto";
+import "validate/validate.proto";
+
+import "authzed/api/v1/core.proto";
+
+// PermissionsService implements a set of RPCs that perform operations on
+// relationships and permissions.
+service PermissionsService {
+ // ReadRelationships reads a set of the relationships matching one or more
+ // filters.
+ rpc ReadRelationships(ReadRelationshipsRequest)
+ returns (stream ReadRelationshipsResponse) {
+ option (google.api.http) = {
+ post: "/v1/relationships/read"
+ body: "*"
+ };
+ }
+
+ // WriteRelationships atomically writes and/or deletes a set of specified
+ // relationships. An optional set of preconditions can be provided that must
+ // be satisfied for the operation to commit.
+ rpc WriteRelationships(WriteRelationshipsRequest)
+ returns (WriteRelationshipsResponse) {
+ option (google.api.http) = {
+ post: "/v1/relationships/write"
+ body: "*"
+ };
+ }
+
+ // DeleteRelationships atomically bulk deletes all relationships matching the
+ // provided filter. If no relationships match, none will be deleted and the
+ // operation will succeed. An optional set of preconditions can be provided that must
+ // be satisfied for the operation to commit.
+ rpc DeleteRelationships(DeleteRelationshipsRequest)
+ returns (DeleteRelationshipsResponse) {
+ option (google.api.http) = {
+ post: "/v1/relationships/delete"
+ body: "*"
+ };
+ }
+
+ // CheckPermission determines for a given resource whether a subject computes
+ // to having a permission or is a direct member of a particular relation.
+ rpc CheckPermission(CheckPermissionRequest)
+ returns (CheckPermissionResponse) {
+ option (google.api.http) = {
+ post: "/v1/permissions/check"
+ body: "*"
+ };
+ }
+
+ // ExpandPermissionTree reveals the graph structure for a resource's
+ // permission or relation. This RPC does not recurse infinitely deep and may
+ // require multiple calls to fully unnest a deeply nested graph.
+ rpc ExpandPermissionTree(ExpandPermissionTreeRequest)
+ returns (ExpandPermissionTreeResponse) {
+ option (google.api.http) = {
+ post: "/v1/permissions/expand"
+ body: "*"
+ };
+ }
+
+ // LookupResources returns all the resources of a given type that a subject
+ // can access whether via a computed permission or relation membership.
+ rpc LookupResources(LookupResourcesRequest)
+ returns (stream LookupResourcesResponse) {
+ option (google.api.http) = {
+ post: "/v1/permissions/resources"
+ body: "*"
+ };
+ }
+
+ // LookupSubjects returns all the subjects of a given type that
+ // have access whether via a computed permission or relation membership.
+ rpc LookupSubjects(LookupSubjectsRequest)
+ returns (stream LookupSubjectsResponse) {
+ option (google.api.http) = {
+ post: "/v1/permissions/subjects"
+ body: "*"
+ };
+ }
+}
+
+// Consistency will define how a request is handled by the backend.
+// By defining a consistency requirement, and a token at which those
+// requirements should be applied, where applicable.
+message Consistency {
+ oneof requirement {
+ option (validate.required) = true;
+
+ // minimize_latency indicates that the latency for the call should be
+ // minimized by having the system select the fastest snapshot available.
+ bool minimize_latency = 1 [ (validate.rules).bool.const = true ];
+
+ // at_least_as_fresh indicates that all data used in the API call must be
+ // *at least as fresh* as that found in the ZedToken; more recent data might
+ // be used if available or faster.
+ ZedToken at_least_as_fresh = 2;
+
+ // at_exact_snapshot indicates that all data used in the API call must be
+ // *at the given* snapshot in time; if the snapshot is no longer available,
+ // an error will be returned to the caller.
+ ZedToken at_exact_snapshot = 3;
+
+ // fully_consistent indicates that all data used in the API call *must* be
+ // at the most recent snapshot found.
+ //
+ // NOTE: using this method can be *quite slow*, so unless there is a need to
+ // do so, it is recommended to use `at_least_as_fresh` with a stored
+ // ZedToken.
+ bool fully_consistent = 4 [ (validate.rules).bool.const = true ];
+ }
+}
+
+// RelationshipFilter is a collection of filters which when applied to a
+// relationship will return relationships that have exactly matching fields.
+//
+// resource_type is required. All other fields are optional and if left
+// unspecified will not filter relationships.
+message RelationshipFilter {
+ string resource_type = 1 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+
+ string optional_resource_id = 2 [ (validate.rules).string = {
+ pattern : "^([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})?$",
+ max_bytes : 128,
+ } ];
+
+ string optional_relation = 3 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
+ max_bytes : 64,
+ } ];
+
+ SubjectFilter optional_subject_filter = 4;
+}
+
+// SubjectFilter specifies a filter on the subject of a relationship.
+//
+// subject_type is required and all other fields are optional, and will not
+// impose any additional requirements if left unspecified.
+message SubjectFilter {
+ message RelationFilter {
+ string relation = 1 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
+ max_bytes : 64,
+ } ];
+ }
+
+ string subject_type = 1 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+
+ string optional_subject_id = 2 [ (validate.rules).string = {
+ pattern : "^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)?$",
+ max_bytes : 128,
+ } ];
+
+ RelationFilter optional_relation = 3;
+}
+
+// ReadRelationshipsRequest specifies one or more filters used to read matching
+// relationships within the system.
+message ReadRelationshipsRequest {
+ Consistency consistency = 1;
+ RelationshipFilter relationship_filter = 2
+ [ (validate.rules).message.required = true ];
+}
+
+// ReadRelationshipsResponse contains a Relationship found that matches the
+// specified relationship filter(s). A instance of this response message will
+// be streamed to the client for each relationship found.
+message ReadRelationshipsResponse {
+ ZedToken read_at = 1 [ (validate.rules).message.required = true ];
+ Relationship relationship = 2 [ (validate.rules).message.required = true ];
+}
+
+// Precondition specifies how and the existence or absence of certain
+// relationships as expressed through the accompanying filter should affect
+// whether or not the operation proceeds.
+//
+// MUST_NOT_MATCH will fail the parent request if any relationships match the
+// relationships filter.
+// MUST_MATCH will fail the parent request if there are no
+// relationships that match the filter.
+message Precondition {
+ enum Operation {
+ OPERATION_UNSPECIFIED = 0;
+ OPERATION_MUST_NOT_MATCH = 1;
+ OPERATION_MUST_MATCH = 2;
+ }
+
+ Operation operation = 1 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+ RelationshipFilter filter = 2 [ (validate.rules).message.required = true ];
+}
+
+// WriteRelationshipsRequest contains a list of Relationship mutations that
+// should be applied to the service. If the optional_preconditions parameter
+// is included, all of the specified preconditions must also be satisfied before
+// the write will be committed.
+message WriteRelationshipsRequest {
+ repeated RelationshipUpdate updates = 1
+ [ (validate.rules).repeated .items.message.required = true ];
+
+ repeated Precondition optional_preconditions = 2
+ [ (validate.rules).repeated .items.message.required =
+ true ]; // To be bounded by configuration
+}
+
+message WriteRelationshipsResponse { ZedToken written_at = 1; }
+
+// DeleteRelationshipsRequest specifies which Relationships should be deleted,
+// requesting the delete of *ALL* relationships that match the specified
+// filters. If the optional_preconditions parameter is included, all of the
+// specified preconditions must also be satisfied before the delete will be
+// executed.
+message DeleteRelationshipsRequest {
+ RelationshipFilter relationship_filter = 1
+ [ (validate.rules).message.required = true ];
+
+ repeated Precondition optional_preconditions = 2
+ [ (validate.rules).repeated .items.message.required =
+ true ]; // To be bounded by configuration
+}
+
+message DeleteRelationshipsResponse { ZedToken deleted_at = 1; }
+
+// CheckPermissionRequest issues a check on whether a subject has a permission
+// or is a member of a relation, on a specific resource.
+message CheckPermissionRequest {
+ Consistency consistency = 1;
+
+ // resource is the resource on which to check the permission or relation.
+ ObjectReference resource = 2 [ (validate.rules).message.required = true ];
+
+ // permission is the name of the permission (or relation) on which to execute
+ // the check.
+ string permission = 3 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
+ max_bytes : 64,
+ } ];
+
+ // subject is the subject that will be checked for the permission or relation.
+ SubjectReference subject = 4 [ (validate.rules).message.required = true ];
+
+ /** context consists of named values that are injected into the caveat evaluation context **/
+ google.protobuf.Struct context = 5 [ (validate.rules).message.required = false ];
+}
+
+message CheckPermissionResponse {
+ enum Permissionship {
+ PERMISSIONSHIP_UNSPECIFIED = 0;
+ PERMISSIONSHIP_NO_PERMISSION = 1;
+ PERMISSIONSHIP_HAS_PERMISSION = 2;
+ PERMISSIONSHIP_CONDITIONAL_PERMISSION = 3;
+ }
+
+ ZedToken checked_at = 1 [ (validate.rules).message.required = false ];
+
+ // Permissionship communicates whether or not the subject has the requested
+ // permission or has a relationship with the given resource, over the given
+ // relation.
+ //
+ // This value will be authzed.api.v1.PERMISSIONSHIP_HAS_PERMISSION if the
+ // requested subject is a member of the computed permission set or there
+ // exists a relationship with the requested relation from the given resource
+ // to the given subject.
+ Permissionship permissionship = 2 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+
+ // partial_caveat_info holds information of a partially-evaluated caveated response
+ PartialCaveatInfo partial_caveat_info = 3 [ (validate.rules).message.required = false ];
+}
+
+// ExpandPermissionTreeRequest returns a tree representing the expansion of all
+// relationships found accessible from a permission or relation on a particular
+// resource.
+//
+// ExpandPermissionTreeRequest is typically used to determine the full set of
+// subjects with a permission, along with the relationships that grant said
+// access.
+message ExpandPermissionTreeRequest {
+ Consistency consistency = 1;
+
+ // resource is the resource over which to run the expansion.
+ ObjectReference resource = 2 [ (validate.rules).message.required = true ];
+
+ // permission is the name of the permission or relation over which to run the
+ // expansion for the resource.
+ string permission = 3 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
+ max_bytes : 64,
+ } ];
+}
+
+message ExpandPermissionTreeResponse {
+ ZedToken expanded_at = 1;
+
+ // tree_root is a tree structure whose leaf nodes are subjects, and
+ // intermediate nodes represent the various operations (union, intersection,
+ // exclusion) to reach those subjects.
+ PermissionRelationshipTree tree_root = 2;
+}
+
+// LookupResourcesRequest performs a lookup of all resources of a particular
+// kind on which the subject has the specified permission or the relation in
+// which the subject exists, streaming back the IDs of those resources.
+message LookupResourcesRequest {
+ Consistency consistency = 1;
+
+ // resource_object_type is the type of resource object for which the IDs will
+ // be returned.
+ string resource_object_type = 2 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+
+ // permission is the name of the permission or relation for which the subject
+ // must Check.
+ string permission = 3 [ (validate.rules).string = {
+ pattern : "^[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 64,
+ } ];
+
+ // subject is the subject with access to the resources.
+ SubjectReference subject = 4 [ (validate.rules).message.required = true ];
+
+ /** context consists of named values that are injected into the caveat evaluation context **/
+ google.protobuf.Struct context = 5 [ (validate.rules).message.required = false ];
+}
+
+// LookupPermissionship represents whether a Lookup response was partially evaluated or not
+enum LookupPermissionship {
+ LOOKUP_PERMISSIONSHIP_UNSPECIFIED = 0;
+ LOOKUP_PERMISSIONSHIP_HAS_PERMISSION = 1;
+ LOOKUP_PERMISSIONSHIP_CONDITIONAL_PERMISSION = 2;
+}
+
+// LookupResourcesResponse contains a single matching resource object ID for the
+// requested object type, permission, and subject.
+message LookupResourcesResponse {
+ ZedToken looked_up_at = 1;
+ string resource_object_id = 2;
+
+ // permissionship indicates whether the response was partially evaluated or not
+ LookupPermissionship permissionship = 3 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+
+ // partial_caveat_info holds information of a partially-evaluated caveated response
+ PartialCaveatInfo partial_caveat_info = 4 [ (validate.rules).message.required = false ];
+}
+
+// LookupSubjectsRequest performs a lookup of all subjects of a particular
+// kind for which the subject has the specified permission or the relation in
+// which the subject exists, streaming back the IDs of those subjects.
+message LookupSubjectsRequest {
+ Consistency consistency = 1;
+
+ // resource is the resource for which all matching subjects for the permission
+ // or relation will be returned.
+ ObjectReference resource = 2 [ (validate.rules).message.required = true ];
+
+ // permission is the name of the permission (or relation) for which to find
+ // the subjects.
+ string permission = 3 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
+ max_bytes : 64,
+ } ];
+
+ // subject_object_type is the type of subject object for which the IDs will
+ // be returned.
+ string subject_object_type = 4 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+
+ // optional_subject_relation is the optional relation for the subject.
+ string optional_subject_relation = 5 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$",
+ max_bytes : 64,
+ } ];
+
+ /** context consists of named values that are injected into the caveat evaluation context **/
+ google.protobuf.Struct context = 6 [ (validate.rules).message.required = false ];
+}
+
+// LookupSubjectsResponse contains a single matching subject object ID for the
+// requested subject object type on the permission or relation.
+message LookupSubjectsResponse {
+ ZedToken looked_up_at = 1;
+
+ // subject_object_id is the Object ID of the subject found. May be a `*` if
+ // a wildcard was found.
+ // deprecated: use `subject`
+ string subject_object_id = 2 [deprecated = true];
+
+ // excluded_subject_ids are the Object IDs of the subjects excluded. This list
+ // will only contain object IDs if `subject_object_id` is a wildcard (`*`) and
+ // will only be populated if exclusions exist from the wildcard.
+ // deprecated: use `excluded_subjects`
+ repeated string excluded_subject_ids = 3 [deprecated = true];
+
+ // permissionship indicates whether the response was partially evaluated or not
+ // deprecated: use `subject.permissionship`
+ LookupPermissionship permissionship = 4 [ deprecated = true, (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+
+ // partial_caveat_info holds information of a partially-evaluated caveated response
+ // deprecated: use `subject.partial_caveat_info`
+ PartialCaveatInfo partial_caveat_info = 5 [ deprecated = true, (validate.rules).message.required = false ];
+
+ // subject is the subject found, along with its permissionship.
+ ResolvedSubject subject = 6;
+
+ // excluded_subjects are the subjects excluded. This list
+ // will only contain subjects if `subject.subject_object_id` is a wildcard (`*`) and
+ // will only be populated if exclusions exist from the wildcard.
+ repeated ResolvedSubject excluded_subjects = 7;
+}
+
+// ResolvedSubject is a single subject resolved within LookupSubjects.
+message ResolvedSubject {
+ // subject_object_id is the Object ID of the subject found. May be a `*` if
+ // a wildcard was found.
+ string subject_object_id = 1;
+
+ // permissionship indicates whether the response was partially evaluated or not
+ LookupPermissionship permissionship = 2 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ];
+
+ // partial_caveat_info holds information of a partially-evaluated caveated response
+ PartialCaveatInfo partial_caveat_info = 3 [ (validate.rules).message.required = false ];
+} \ No newline at end of file
diff --git a/crates/secd/proto/authzed/api/v1/schema_service.proto b/crates/secd/proto/authzed/api/v1/schema_service.proto
new file mode 100644
index 0000000..ed60a0d
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1/schema_service.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+package authzed.api.v1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
+option java_package = "com.authzed.api.v1";
+
+import "google/api/annotations.proto";
+import "validate/validate.proto";
+
+// SchemaService implements operations on a Permissions System's Schema.
+service SchemaService {
+ // Read returns the current Object Definitions for a Permissions System.
+ //
+ // Errors include:
+ // - INVALID_ARGUMENT: a provided value has failed to semantically validate
+ // - NOT_FOUND: no schema has been defined
+ rpc ReadSchema(ReadSchemaRequest) returns (ReadSchemaResponse) {
+ option (google.api.http) = {
+ post: "/v1/schema/read"
+ body: "*"
+ };
+ }
+
+ // Write overwrites the current Object Definitions for a Permissions System.
+ rpc WriteSchema(WriteSchemaRequest) returns (WriteSchemaResponse) {
+ option (google.api.http) = {
+ post: "/v1/schema/write"
+ body: "*"
+ };
+ }
+}
+
+// ReadSchemaRequest returns the schema from the database.
+message ReadSchemaRequest {}
+
+// ReadSchemaResponse is the resulting data after having read the Object
+// Definitions from a Schema.
+message ReadSchemaResponse {
+ // schema_text is the textual form of the current schema in the system
+ string schema_text = 1;
+}
+
+// WriteSchemaRequest is the required data used to "upsert" the Schema of a
+// Permissions System.
+message WriteSchemaRequest {
+ // The Schema containing one or more Object Definitions that will be written
+ // to the Permissions System.
+ string schema = 1 [ (validate.rules).string.max_bytes = 262144 ]; // 256KiB
+}
+
+// WriteSchemaResponse is the resulting data after having written a Schema to
+// a Permissions System.
+message WriteSchemaResponse {}
diff --git a/crates/secd/proto/authzed/api/v1/watch_service.proto b/crates/secd/proto/authzed/api/v1/watch_service.proto
new file mode 100644
index 0000000..21aaccd
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1/watch_service.proto
@@ -0,0 +1,44 @@
+syntax = "proto3";
+package authzed.api.v1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1";
+option java_package = "com.authzed.api.v1";
+
+import "google/api/annotations.proto";
+import "validate/validate.proto";
+
+import "authzed/api/v1/core.proto";
+
+service WatchService {
+ rpc Watch(WatchRequest) returns (stream WatchResponse) {
+ option (google.api.http) = {
+ post: "/v1/watch"
+ body: "*"
+ };
+ }
+}
+
+// WatchRequest specifies the object definitions for which we want to start
+// watching mutations, and an optional start snapshot for when to start
+// watching.
+message WatchRequest {
+ repeated string optional_object_types = 1 [
+ (validate.rules).repeated .min_items = 0,
+ (validate.rules).repeated .items.string = {
+ pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9]/"
+ ")?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ }
+ ];
+
+ ZedToken optional_start_cursor = 2;
+}
+
+// WatchResponse contains all tuple modification events in ascending
+// timestamp order, from the requested start snapshot to a snapshot
+// encoded in the watch response. The client can use the snapshot to resume
+// watching where the previous watch response left off.
+message WatchResponse {
+ repeated RelationshipUpdate updates = 1;
+ ZedToken changes_through = 2;
+}
diff --git a/crates/secd/proto/authzed/api/v1alpha1/schema.proto b/crates/secd/proto/authzed/api/v1alpha1/schema.proto
new file mode 100644
index 0000000..969ecdb
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1alpha1/schema.proto
@@ -0,0 +1,68 @@
+syntax = "proto3";
+package authzed.api.v1alpha1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1alpha1";
+option java_package = "com.authzed.api.v1alpha1";
+
+import "validate/validate.proto";
+
+// SchemaService implements operations on a Permissions System's Schema.
+service SchemaService {
+ // Read returns the current Object Definitions for a Permissions System.
+ //
+ // Errors include:
+ // - INVALID_ARGUMENT: a provided value has failed to semantically validate
+ // - NOT_FOUND: one of the Object Definitions being requested does not exist
+ rpc ReadSchema(ReadSchemaRequest) returns (ReadSchemaResponse) {}
+
+ // Write overwrites the current Object Definitions for a Permissions System.
+ //
+ // Any Object Definitions that exist, but are not included will be deleted.
+ rpc WriteSchema(WriteSchemaRequest) returns (WriteSchemaResponse) {}
+}
+
+// ReadSchemaRequest is the required data to read Object Definitions from
+// a Schema.
+message ReadSchemaRequest {
+ // The list of names of the Object Definitions that are being requested.
+ //
+ // These names must be fully qualified with their namespace (e.g.
+ // myblog/post).
+ repeated string object_definitions_names = 1 [ (validate.rules).repeated .items.string = {
+ pattern: "^([a-z][a-z0-9_]{1,62}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes: 128,
+ } ];
+}
+
+// ReadSchemaResponse is the resulting data after having read the Object
+// Definitions from a Schema.
+message ReadSchemaResponse {
+ // The Object Definitions that were requested.
+ repeated string object_definitions = 1;
+
+ // The computed revision of the returned object definitions.
+ string computed_definitions_revision = 2;
+}
+
+// WriteSchemaRequest is the required data used to "upsert" the Schema of a
+// Permissions System.
+message WriteSchemaRequest {
+ // The Schema containing one or more Object Definitions that will be written
+ // to the Permissions System.
+ string schema = 1 [ (validate.rules).string.max_bytes = 262144 ]; // 256KiB
+
+ // If specified, the existing revision of object definitions in the schema that must be present for
+ // the write to succeed. If the revision specified differs (i.e. the underlying schema has changed),
+ // the write call will fail with a FAILED_PRECONDITION error.
+ string optional_definitions_revision_precondition = 2;
+}
+
+// WriteSchemaResponse is the resulting data after having written a Schema to
+// a Permissions System.
+message WriteSchemaResponse {
+ // The names of the Object Definitions that were written.
+ repeated string object_definitions_names = 1;
+
+ // The computed revision of the written object definitions.
+ string computed_definitions_revision = 2;
+}
diff --git a/crates/secd/proto/authzed/api/v1alpha1/watchresources_service.proto b/crates/secd/proto/authzed/api/v1alpha1/watchresources_service.proto
new file mode 100644
index 0000000..27c028a
--- /dev/null
+++ b/crates/secd/proto/authzed/api/v1alpha1/watchresources_service.proto
@@ -0,0 +1,83 @@
+syntax = "proto3";
+package authzed.api.v1alpha1;
+
+option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1alpha1";
+option java_package = "com.authzed.api.v1alpha1";
+
+import "google/api/annotations.proto";
+import "validate/validate.proto";
+
+import "authzed/api/v1/core.proto";
+
+// WatchResourcesService is used to receive a stream of updates for resources of a
+// specific (resource type, permission, subject) combination.
+service WatchResourcesService {
+
+ // WatchResources initiates a watch for permission changes for the provided
+ // (resource type, permission, subject) pair.
+ rpc WatchResources(WatchResourcesRequest)
+ returns (stream WatchResourcesResponse) {
+ option (google.api.http) = {
+ post: "/v1alpha1/lookupwatch"
+ body: "*"
+ };
+ }
+}
+
+// WatchResourcesRequest starts a watch for specific permission updates
+// for the given resource and subject types.
+message WatchResourcesRequest {
+
+ // resource_object_type is the type of resource object for which we will
+ // watch for changes.
+ string resource_object_type = 1 [ (validate.rules).string = {
+ pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 128,
+ } ];
+
+ // permission is the name of the permission or relation for which we will
+ // watch for changes.
+ string permission = 2 [ (validate.rules).string = {
+ pattern : "^[a-z][a-z0-9_]{1,62}[a-z0-9]$",
+ max_bytes : 64,
+ } ];
+
+ // subject_object_type is the type of the subject resource for which we will
+ // watch for changes.
+ string subject_object_type = 3;
+
+ // optional_subject_relation allows you to specify a group of subjects to watch
+ // for a given subject type.
+ string optional_subject_relation = 4;
+
+ authzed.api.v1.ZedToken optional_start_cursor = 5;
+}
+
+// PermissionUpdate represents a single permission update for a specific
+// subject's permissions.
+message PermissionUpdate {
+
+ // todo: work this into the v1 core API at some point since it's used
+ // across services.
+ enum Permissionship {
+ PERMISSIONSHIP_UNSPECIFIED = 0;
+ PERMISSIONSHIP_NO_PERMISSION = 1;
+ PERMISSIONSHIP_HAS_PERMISSION = 2;
+ }
+
+ // subject defines the subject resource whose permissions have changed.
+ authzed.api.v1.SubjectReference subject = 1;
+
+ // resource defines the specific object in the system.
+ authzed.api.v1.ObjectReference resource = 2;
+
+ string relation = 3;
+ Permissionship updated_permission = 4;
+}
+
+// WatchResourcesResponse enumerates the list of permission updates that have
+// occurred as a result of one or more relationship updates.
+message WatchResourcesResponse {
+ repeated PermissionUpdate updates = 1;
+ authzed.api.v1.ZedToken changes_through = 2;
+} \ No newline at end of file