diff --git a/.github/workflows/automatic-api-update.yaml b/.github/workflows/automatic-api-update.yaml index 369c9d0..90352d8 100644 --- a/.github/workflows/automatic-api-update.yaml +++ b/.github/workflows/automatic-api-update.yaml @@ -1,3 +1,4 @@ +--- name: "Called update for API change" on: repository_dispatch: @@ -10,6 +11,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 + - uses: bahmutov/npm-install@v1 + with: + useLockFile: false - name: "Update Buf Script" id: buf-update uses: authzed/actions/buf-api-update@main @@ -29,7 +33,7 @@ jobs: if: steps.buf-update.outputs.updated == 'true' - name: "Run buf generate" if: steps.buf-update.outputs.updated == 'true' - run: "buf generate" + run: "yarn run buf" - name: Create Pull Request uses: peter-evans/create-pull-request@v7.0.6 if: steps.buf-update.outputs.updated == 'true' diff --git a/buf.gen.yaml b/buf.gen.yaml index 2e4e139..02367b3 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -8,7 +8,7 @@ plugins: - long_type_string - client_grpc1 inputs: - - module: "buf.build/authzed/api:v1.38.0" + - module: "buf.build/authzed/api:v1.40.0" paths: # NOTE: This grabs only the v1 proto and ignores v0 and v1dev. - "authzed/api/v1" diff --git a/src/authzedapi/authzed/api/v1/core.ts b/src/authzedapi/authzed/api/v1/core.ts index b9c03c2..6d8c9df 100644 --- a/src/authzedapi/authzed/api/v1/core.ts +++ b/src/authzedapi/authzed/api/v1/core.ts @@ -12,6 +12,7 @@ import { reflectionMergePartial } from "@protobuf-ts/runtime"; import { MESSAGE_TYPE } from "@protobuf-ts/runtime"; import { MessageType } from "@protobuf-ts/runtime"; import { Struct } from "../../../google/protobuf/struct.js"; +import { Timestamp } from "../../../google/protobuf/timestamp.js"; /** * Relationship specifies how a resource relates to a subject. Relationships * form the data for the graph over which all permissions questions are @@ -39,11 +40,17 @@ export interface Relationship { */ subject?: SubjectReference; /** - * optional_caveat is a reference to a the caveat that must be enforced over the relationship + * optional_caveat is a reference to a the caveat that must be enforced over the relationship. * * @generated from protobuf field: authzed.api.v1.ContextualizedCaveat optional_caveat = 4; */ optionalCaveat?: ContextualizedCaveat; + /** + * optional_expires_at is the time at which the relationship expires, if any. + * + * @generated from protobuf field: google.protobuf.Timestamp optional_expires_at = 5; + */ + optionalExpiresAt?: Timestamp; } /** * ContextualizedCaveat represents a reference to a caveat to be used by caveated relationships. @@ -282,7 +289,8 @@ class Relationship$Type extends MessageType { { no: 1, name: "resource", kind: "message", T: () => ObjectReference, options: { "validate.rules": { message: { required: true } } } }, { no: 2, name: "relation", kind: "scalar", T: 9 /*ScalarType.STRING*/, options: { "validate.rules": { string: { maxBytes: "64", pattern: "^[a-z][a-z0-9_]{1,62}[a-z0-9]$" } } } }, { no: 3, name: "subject", kind: "message", T: () => SubjectReference, options: { "validate.rules": { message: { required: true } } } }, - { no: 4, name: "optional_caveat", kind: "message", T: () => ContextualizedCaveat, options: { "validate.rules": { message: { required: false } } } } + { no: 4, name: "optional_caveat", kind: "message", T: () => ContextualizedCaveat, options: { "validate.rules": { message: { required: false } } } }, + { no: 5, name: "optional_expires_at", kind: "message", T: () => Timestamp } ]); } create(value?: PartialMessage): Relationship { @@ -309,6 +317,9 @@ class Relationship$Type extends MessageType { case /* authzed.api.v1.ContextualizedCaveat optional_caveat */ 4: message.optionalCaveat = ContextualizedCaveat.internalBinaryRead(reader, reader.uint32(), options, message.optionalCaveat); break; + case /* google.protobuf.Timestamp optional_expires_at */ 5: + message.optionalExpiresAt = Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.optionalExpiresAt); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -333,6 +344,9 @@ class Relationship$Type extends MessageType { /* authzed.api.v1.ContextualizedCaveat optional_caveat = 4; */ if (message.optionalCaveat) ContextualizedCaveat.internalBinaryWrite(message.optionalCaveat, writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* google.protobuf.Timestamp optional_expires_at = 5; */ + if (message.optionalExpiresAt) + Timestamp.internalBinaryWrite(message.optionalExpiresAt, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); diff --git a/src/authzedapi/authzed/api/v1/debug.ts b/src/authzedapi/authzed/api/v1/debug.ts index 511d58f..c89e1b6 100644 --- a/src/authzedapi/authzed/api/v1/debug.ts +++ b/src/authzedapi/authzed/api/v1/debug.ts @@ -13,6 +13,7 @@ import { MESSAGE_TYPE } from "@protobuf-ts/runtime"; import { MessageType } from "@protobuf-ts/runtime"; import { PartialCaveatInfo } from "./core.js"; import { Struct } from "../../../google/protobuf/struct.js"; +import { Timestamp } from "../../../google/protobuf/timestamp.js"; import { Duration } from "../../../google/protobuf/duration.js"; import { SubjectReference } from "./core.js"; import { ObjectReference } from "./core.js"; @@ -49,6 +50,8 @@ export interface DebugInformation { export interface CheckDebugTrace { /** * resource holds the resource on which the Check was performed. + * for batched calls, the object_id field contains a comma-separated list of object IDs + * for all the resources checked in the batch. * * @generated from protobuf field: authzed.api.v1.ObjectReference resource = 1; */ @@ -113,6 +116,34 @@ export interface CheckDebugTrace { } | { oneofKind: undefined; }; + /** + * optional_expires_at is the time at which at least one of the relationships used to + * compute this result, expires (if any). This is *not* related to the caching window. + * + * @generated from protobuf field: google.protobuf.Timestamp optional_expires_at = 10; + */ + optionalExpiresAt?: Timestamp; + /** + * trace_operation_id is a unique identifier for this trace's operation, that will + * be shared for all traces created for the same check operation in SpiceDB. + * + * In cases where SpiceDB performs automatic batching of subproblems, this ID can be used + * to correlate work that was shared across multiple traces. + * + * This identifier is generated by SpiceDB, is to be considered opaque to the caller + * and only guaranteed to be unique within the same overall Check or CheckBulk operation. + * + * @generated from protobuf field: string trace_operation_id = 11; + */ + traceOperationId: string; + /** + * source holds the source of the result. It is of the form: + * `:`, where sourcetype can be, among others: + * `spicedb`, `materialize`, etc. + * + * @generated from protobuf field: string source = 12; + */ + source: string; } /** * @generated from protobuf message authzed.api.v1.CheckDebugTrace.SubProblems @@ -289,11 +320,14 @@ class CheckDebugTrace$Type extends MessageType { { no: 8, name: "caveat_evaluation_info", kind: "message", T: () => CaveatEvalInfo }, { no: 9, name: "duration", kind: "message", T: () => Duration }, { no: 6, name: "was_cached_result", kind: "scalar", oneof: "resolution", T: 8 /*ScalarType.BOOL*/ }, - { no: 7, name: "sub_problems", kind: "message", oneof: "resolution", T: () => CheckDebugTrace_SubProblems } + { no: 7, name: "sub_problems", kind: "message", oneof: "resolution", T: () => CheckDebugTrace_SubProblems }, + { no: 10, name: "optional_expires_at", kind: "message", T: () => Timestamp }, + { no: 11, name: "trace_operation_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 12, name: "source", kind: "scalar", T: 9 /*ScalarType.STRING*/ } ]); } create(value?: PartialMessage): CheckDebugTrace { - const message = { permission: "", permissionType: 0, result: 0, resolution: { oneofKind: undefined } }; + const message = { permission: "", permissionType: 0, result: 0, resolution: { oneofKind: undefined }, traceOperationId: "", source: "" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); @@ -337,6 +371,15 @@ class CheckDebugTrace$Type extends MessageType { subProblems: CheckDebugTrace_SubProblems.internalBinaryRead(reader, reader.uint32(), options, (message.resolution as any).subProblems) }; break; + case /* google.protobuf.Timestamp optional_expires_at */ 10: + message.optionalExpiresAt = Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.optionalExpiresAt); + break; + case /* string trace_operation_id */ 11: + message.traceOperationId = reader.string(); + break; + case /* string source */ 12: + message.source = reader.string(); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -376,6 +419,15 @@ class CheckDebugTrace$Type extends MessageType { /* authzed.api.v1.CheckDebugTrace.SubProblems sub_problems = 7; */ if (message.resolution.oneofKind === "subProblems") CheckDebugTrace_SubProblems.internalBinaryWrite(message.resolution.subProblems, writer.tag(7, WireType.LengthDelimited).fork(), options).join(); + /* google.protobuf.Timestamp optional_expires_at = 10; */ + if (message.optionalExpiresAt) + Timestamp.internalBinaryWrite(message.optionalExpiresAt, writer.tag(10, WireType.LengthDelimited).fork(), options).join(); + /* string trace_operation_id = 11; */ + if (message.traceOperationId !== "") + writer.tag(11, WireType.LengthDelimited).string(message.traceOperationId); + /* string source = 12; */ + if (message.source !== "") + writer.tag(12, WireType.LengthDelimited).string(message.source); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); diff --git a/src/authzedapi/authzed/api/v1/experimental_service.ts b/src/authzedapi/authzed/api/v1/experimental_service.ts index 7e37ac5..c87635e 100644 --- a/src/authzedapi/authzed/api/v1/experimental_service.ts +++ b/src/authzedapi/authzed/api/v1/experimental_service.ts @@ -211,9 +211,10 @@ export interface BulkCheckPermissionResponseItem { * BulkImportRelationshipsRequest represents one batch of the streaming * BulkImportRelationships API. The maximum size is only limited by the backing * datastore, and optimal size should be determined by the calling client - * experimentally. Any relationships within the same request are guaranteed to - * be written in a single transaction. If any of the relationships already - * exist, the transaction will fail and no relationships will be written. + * experimentally. When BulkImport is invoked and receives its first request message, + * a transaction is opened to import the relationships. All requests sent to the same + * invocation are executed under this single transaction. If a relationship already + * exists within the datastore, the entire transaction will fail with an error. * * @generated from protobuf message authzed.api.v1.BulkImportRelationshipsRequest */ diff --git a/src/authzedapi/authzed/api/v1/permission_service.ts b/src/authzedapi/authzed/api/v1/permission_service.ts index 2bf4567..4a452b8 100644 --- a/src/authzedapi/authzed/api/v1/permission_service.ts +++ b/src/authzedapi/authzed/api/v1/permission_service.ts @@ -14,6 +14,7 @@ import { MESSAGE_TYPE } from "@protobuf-ts/runtime"; import { MessageType } from "@protobuf-ts/runtime"; import { PermissionRelationshipTree } from "./core.js"; import { Status } from "../../../google/rpc/status.js"; +import { Timestamp } from "../../../google/protobuf/timestamp.js"; import { DebugInformation } from "./debug.js"; import { PartialCaveatInfo } from "./core.js"; import { SubjectReference } from "./core.js"; @@ -461,6 +462,13 @@ export interface CheckPermissionResponse { * @generated from protobuf field: authzed.api.v1.DebugInformation debug_trace = 4; */ debugTrace?: DebugInformation; + /** + * optional_expires_at is the time at which at least one of the relationships used to + * compute this result, expires (if any). This is *not* related to the caching window. + * + * @generated from protobuf field: google.protobuf.Timestamp optional_expires_at = 5; + */ + optionalExpiresAt?: Timestamp; } /** * @generated from protobuf enum authzed.api.v1.CheckPermissionResponse.Permissionship @@ -501,6 +509,14 @@ export interface CheckBulkPermissionsRequest { * @generated from protobuf field: repeated authzed.api.v1.CheckBulkPermissionsRequestItem items = 2; */ items: CheckBulkPermissionsRequestItem[]; + /** + * with_tracing, if true, indicates that each response should include a debug trace. + * This can be useful for debugging and performance analysis, but adds a small amount + * of compute overhead to the request. + * + * @generated from protobuf field: bool with_tracing = 3; + */ + withTracing: boolean; } /** * @generated from protobuf message authzed.api.v1.CheckBulkPermissionsRequestItem @@ -575,6 +591,12 @@ export interface CheckBulkPermissionsResponseItem { * @generated from protobuf field: authzed.api.v1.PartialCaveatInfo partial_caveat_info = 2; */ partialCaveatInfo?: PartialCaveatInfo; + /** + * debug_trace is the debugging trace of this check, if requested. + * + * @generated from protobuf field: authzed.api.v1.DebugInformation debug_trace = 3; + */ + debugTrace?: DebugInformation; } /** * ExpandPermissionTreeRequest returns a tree representing the expansion of all @@ -919,7 +941,10 @@ export interface ResolvedSubject { * ImportBulkRelationshipsRequest represents one batch of the streaming * ImportBulkRelationships API. The maximum size is only limited by the backing * datastore, and optimal size should be determined by the calling client - * experimentally. + * experimentally. When ImportBulk is invoked and receives its first request message, + * a transaction is opened to import the relationships. All requests sent to the same + * invocation are executed under this single transaction. If a relationship already + * exists within the datastore, the entire transaction will fail with an error. * * @generated from protobuf message authzed.api.v1.ImportBulkRelationshipsRequest */ @@ -1786,7 +1811,8 @@ class CheckPermissionResponse$Type extends MessageType { no: 1, name: "checked_at", kind: "message", T: () => ZedToken, options: { "validate.rules": { message: { required: false } } } }, { no: 2, name: "permissionship", kind: "enum", T: () => ["authzed.api.v1.CheckPermissionResponse.Permissionship", CheckPermissionResponse_Permissionship, "PERMISSIONSHIP_"], options: { "validate.rules": { enum: { definedOnly: true, notIn: [0] } } } }, { no: 3, name: "partial_caveat_info", kind: "message", T: () => PartialCaveatInfo, options: { "validate.rules": { message: { required: false } } } }, - { no: 4, name: "debug_trace", kind: "message", T: () => DebugInformation } + { no: 4, name: "debug_trace", kind: "message", T: () => DebugInformation }, + { no: 5, name: "optional_expires_at", kind: "message", T: () => Timestamp } ]); } create(value?: PartialMessage): CheckPermissionResponse { @@ -1813,6 +1839,9 @@ class CheckPermissionResponse$Type extends MessageType case /* authzed.api.v1.DebugInformation debug_trace */ 4: message.debugTrace = DebugInformation.internalBinaryRead(reader, reader.uint32(), options, message.debugTrace); break; + case /* google.protobuf.Timestamp optional_expires_at */ 5: + message.optionalExpiresAt = Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.optionalExpiresAt); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -1837,6 +1866,9 @@ class CheckPermissionResponse$Type extends MessageType /* authzed.api.v1.DebugInformation debug_trace = 4; */ if (message.debugTrace) DebugInformation.internalBinaryWrite(message.debugTrace, writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* google.protobuf.Timestamp optional_expires_at = 5; */ + if (message.optionalExpiresAt) + Timestamp.internalBinaryWrite(message.optionalExpiresAt, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -1852,11 +1884,12 @@ class CheckBulkPermissionsRequest$Type extends MessageType Consistency }, - { no: 2, name: "items", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => CheckBulkPermissionsRequestItem, options: { "validate.rules": { repeated: { items: { message: { required: true } } } } } } + { no: 2, name: "items", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => CheckBulkPermissionsRequestItem, options: { "validate.rules": { repeated: { items: { message: { required: true } } } } } }, + { no: 3, name: "with_tracing", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } ]); } create(value?: PartialMessage): CheckBulkPermissionsRequest { - const message = { items: [] }; + const message = { items: [], withTracing: false }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); @@ -1873,6 +1906,9 @@ class CheckBulkPermissionsRequest$Type extends MessageType ["authzed.api.v1.CheckPermissionResponse.Permissionship", CheckPermissionResponse_Permissionship, "PERMISSIONSHIP_"], options: { "validate.rules": { enum: { definedOnly: true, notIn: [0] } } } }, - { no: 2, name: "partial_caveat_info", kind: "message", T: () => PartialCaveatInfo, options: { "validate.rules": { message: { required: false } } } } + { no: 2, name: "partial_caveat_info", kind: "message", T: () => PartialCaveatInfo, options: { "validate.rules": { message: { required: false } } } }, + { no: 3, name: "debug_trace", kind: "message", T: () => DebugInformation } ]); } create(value?: PartialMessage): CheckBulkPermissionsResponseItem { @@ -2116,6 +2156,9 @@ class CheckBulkPermissionsResponseItem$Type extends MessageType