diff options
Diffstat (limited to '')
| -rw-r--r-- | crates/secd/proto/authzed/api/v1/core.proto | 145 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1/debug.proto | 103 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1/error_reason.proto | 197 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1/openapi.proto | 43 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1/permission_service.proto | 438 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1/schema_service.proto | 53 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1/watch_service.proto | 44 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1alpha1/schema.proto | 68 | ||||
| -rw-r--r-- | crates/secd/proto/authzed/api/v1alpha1/watchresources_service.proto | 83 |
9 files changed, 1174 insertions, 0 deletions
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 |
