Skip to content

Commit 85d67a6

Browse files
committed
spicedb: set grpc options
1 parent 6f0040e commit 85d67a6

File tree

5 files changed

+76
-61
lines changed

5 files changed

+76
-61
lines changed

components/server/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"/src"
3535
],
3636
"dependencies": {
37-
"@authzed/authzed-node": "^0.10.0",
37+
"@authzed/authzed-node": "^0.12.1",
3838
"@bufbuild/connect": "^0.8.1",
3939
"@bufbuild/connect-express": "^0.8.1",
4040
"@gitbeaker/node": "^35.7.0",
@@ -66,6 +66,7 @@
6666
"express-http-proxy": "^1.0.7",
6767
"fs-extra": "^10.0.0",
6868
"google-protobuf": "^3.19.1",
69+
"@grpc/grpc-js_1_9_0": "npm:@grpc/[email protected]",
6970
"inversify": "^6.0.1",
7071
"ioredis": "^5.3.2",
7172
"ioredis-mock": "^8.7.0",

components/server/src/authorization/authorizer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ export class Authorizer {
474474
optionalSubjectId: relation.subject.object.objectId,
475475
},
476476
},
477+
optionalLimit: 0,
477478
});
478479
if (relationships.length === 0) {
479480
return undefined;
@@ -498,6 +499,7 @@ export class Authorizer {
498499
optionalSubjectId: relation.subject.object.objectId,
499500
},
500501
},
502+
optionalLimit: 0,
501503
});
502504
return relationships.map((r) => r.relationship!);
503505
}

components/server/src/authorization/spicedb-authorizer.ts

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { getExperimentsClientForBackend } from "@gitpod/gitpod-protocol/lib/expe
1212
import { inject, injectable } from "inversify";
1313
import { observeSpicedbClientLatency, spicedbClientLatency } from "../prometheus-metrics";
1414
import { SpiceDBClient } from "./spicedb";
15+
// TODO(gpl) Change to "@grpc/grpc-js" once we can use 1.9.0 (or higher) everywhere
16+
import * as grpc from "@grpc/grpc-js_1_9_0";
1517

1618
@injectable()
1719
export class SpiceDBAuthorizer {
@@ -43,7 +45,7 @@ export class SpiceDBAuthorizer {
4345
const timer = spicedbClientLatency.startTimer();
4446
let error: Error | undefined;
4547
try {
46-
const response = await timeout(this.client.checkPermission(req), 5000);
48+
const response = await this.client.checkPermission(req, this.callOptions);
4749
const permitted = response.permissionship === v1.CheckPermissionResponse_Permissionship.HAS_PERMISSION;
4850

4951
return permitted;
@@ -68,13 +70,11 @@ export class SpiceDBAuthorizer {
6870
const timer = spicedbClientLatency.startTimer();
6971
let error: Error | undefined;
7072
try {
71-
const response = await timeout(
72-
this.client.writeRelationships(
73-
v1.WriteRelationshipsRequest.create({
74-
updates,
75-
}),
76-
),
77-
5000,
73+
const response = await this.client.writeRelationships(
74+
v1.WriteRelationshipsRequest.create({
75+
updates,
76+
}),
77+
this.callOptions,
7878
);
7979
log.info("[spicedb] Successfully wrote relationships.", { response, updates });
8080

@@ -98,25 +98,20 @@ export class SpiceDBAuthorizer {
9898
const timer = spicedbClientLatency.startTimer();
9999
let error: Error | undefined;
100100
try {
101-
return await timeout(
102-
(async () => {
103-
const existing = await client.readRelationships(v1.ReadRelationshipsRequest.create(req));
104-
if (existing.length > 0) {
105-
const response = await client.deleteRelationships(req);
106-
const after = await client.readRelationships(v1.ReadRelationshipsRequest.create(req));
107-
if (after.length > 0) {
108-
log.error("[spicedb] Failed to delete relationships.", { existing, after, request: req });
109-
}
110-
log.info(`[spicedb] Successfully deleted ${existing.length} relationships.`, {
111-
response,
112-
request: req,
113-
existing,
114-
});
115-
}
116-
return existing;
117-
})(),
118-
5000,
119-
);
101+
const existing = await client.readRelationships(v1.ReadRelationshipsRequest.create(req), this.callOptions);
102+
if (existing.length > 0) {
103+
const response = await client.deleteRelationships(req, this.callOptions);
104+
const after = await client.readRelationships(v1.ReadRelationshipsRequest.create(req), this.callOptions);
105+
if (after.length > 0) {
106+
log.error("[spicedb] Failed to delete relationships.", { existing, after, request: req });
107+
}
108+
log.info(`[spicedb] Successfully deleted ${existing.length} relationships.`, {
109+
response,
110+
request: req,
111+
existing,
112+
});
113+
}
114+
return existing;
120115
} catch (err) {
121116
error = err;
122117
// While in we're running two authorization systems in parallel, we do not hard fail on writes.
@@ -133,7 +128,18 @@ export class SpiceDBAuthorizer {
133128
if (!this.client) {
134129
return [];
135130
}
136-
return this.client.readRelationships(req);
131+
return this.client.readRelationships(req, this.callOptions);
132+
}
133+
134+
/**
135+
* permission_service.grpc-client.d.ts has all methods overloaded with this pattern:
136+
* - xyzRelationships(input: Request, metadata?: grpc.Metadata | grpc.CallOptions, options?: grpc.CallOptions): grpc.ClientReadableStream<ReadRelationshipsResponse>;
137+
* But the promisified client somehow does not have the same overloads. Thus we convince it here that options may be passed as 2nd argument.
138+
*/
139+
private get callOptions(): grpc.Metadata {
140+
return {
141+
deadline: Date.now() + 5000,
142+
} as any as grpc.Metadata;
137143
}
138144
}
139145
function startTimer() {
@@ -146,20 +152,20 @@ function stopTimer(method: string, hrtime: [number, number]) {
146152
log.info(`[SPICEDB] ${method} (${ms} ms)`);
147153
}
148154

149-
async function timeout<T>(code: Promise<T>, ms: number): Promise<T> {
150-
return new Promise<T>((resolve, reject) => {
151-
const timer = setTimeout(() => {
152-
reject(new Error(`[spicedb] timed out after ${ms}ms`));
153-
}, ms);
154-
code.then(
155-
(res) => {
156-
clearTimeout(timer);
157-
resolve(res);
158-
},
159-
(err) => {
160-
clearTimeout(timer);
161-
reject(err);
162-
},
163-
);
164-
});
165-
}
155+
// async function timeout<T>(code: Promise<T>, ms: number): Promise<T> {
156+
// return new Promise<T>((resolve, reject) => {
157+
// const timer = setTimeout(() => {
158+
// reject(new Error(`[spicedb] timed out after ${ms}ms`));
159+
// }, ms);
160+
// code.then(
161+
// (res) => {
162+
// clearTimeout(timer);
163+
// resolve(res);
164+
// },
165+
// (err) => {
166+
// clearTimeout(timer);
167+
// reject(err);
168+
// },
169+
// );
170+
// });
171+
// }

components/server/src/authorization/spicedb.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import { v1 } from "@authzed/authzed-node";
8+
import { defaultGRPCOptions } from "@gitpod/gitpod-protocol/lib/util/grpc";
89
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
910

1011
export const SpiceDBClient = Symbol("SpiceDBClient");
@@ -23,5 +24,10 @@ export function spicedbClientFromEnv(): SpiceDBClient {
2324
return undefined;
2425
}
2526

26-
return v1.NewClient(token, address, v1.ClientSecurity.INSECURE_PLAINTEXT_CREDENTIALS).promises;
27+
const clientOptions = {
28+
...defaultGRPCOptions,
29+
};
30+
31+
return v1.NewClient(token, address, v1.ClientSecurity.INSECURE_PLAINTEXT_CREDENTIALS, undefined, clientOptions)
32+
.promises;
2733
}

yarn.lock

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
# yarn lockfile v1
33

44

5-
"@authzed/authzed-node@^0.10.0":
6-
version "0.10.0"
7-
resolved "https://registry.yarnpkg.com/@authzed/authzed-node/-/authzed-node-0.10.0.tgz#623e4911fde221bb526e7f2e9ca335d9f3b9072d"
8-
integrity sha512-TnAnatcU5dHvyGqrWoZzPNaO1opPpVU1y7P5LrJsV2j54y0xvx/OFhYtfeguMxHSz2kpbdCuIvIKJuB8WFbRRA==
5+
"@authzed/authzed-node@^0.12.1":
6+
version "0.12.1"
7+
resolved "https://registry.yarnpkg.com/@authzed/authzed-node/-/authzed-node-0.12.1.tgz#0c28395a64f9b1ecf33faf67259e32a9a3bce300"
8+
integrity sha512-BVHLaPfiHQw1Vz+199m9i4xltT3YyFhqVHtkYPIQ28q8a7iJpnXmFRZIWuTMJcxJI01wtAxJYFuRJq3ktFe6qw==
99
dependencies:
10-
"@grpc/grpc-js" "^1.2.8"
10+
"@grpc/grpc-js" "^1.8.3"
1111
"@protobuf-ts/runtime" "^2.8.1"
1212
"@protobuf-ts/runtime-rpc" "^2.8.1"
1313
google-protobuf "^3.15.3"
@@ -1419,14 +1419,6 @@
14191419
"@grpc/proto-loader" "^0.7.0"
14201420
"@types/node" ">=12.12.47"
14211421

1422-
"@grpc/grpc-js@^1.2.8":
1423-
version "1.8.7"
1424-
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.7.tgz#2154fc0134462ad45f4134e8b54682a25ed05956"
1425-
integrity sha512-dRAWjRFN1Zy9mzPNLkFFIWT8T6C9euwluzCHZUKuhC+Bk3MayNPcpgDRyG+sg+n2sitEUySKxUynirVpu9ItKw==
1426-
dependencies:
1427-
"@grpc/proto-loader" "^0.7.0"
1428-
"@types/node" ">=12.12.47"
1429-
14301422
"@grpc/grpc-js@^1.6.1":
14311423
version "1.7.0"
14321424
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.7.0.tgz#5a96bdbe51cce23faa38a4db6e43595a5c584849"
@@ -1435,6 +1427,14 @@
14351427
"@grpc/proto-loader" "^0.7.0"
14361428
"@types/node" ">=12.12.47"
14371429

1430+
"@grpc/grpc-js@^1.8.3", "@grpc/grpc-js_1_9_0@npm:@grpc/[email protected]":
1431+
version "1.9.0"
1432+
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.0.tgz#bdb599e339adabb16aa7243e70c311f75a572867"
1433+
integrity sha512-H8+iZh+kCE6VR/Krj6W28Y/ZlxoZ1fOzsNt77nrdE3knkbSelW1Uus192xOFCxHyeszLj8i4APQkSIXjAoOxXg==
1434+
dependencies:
1435+
"@grpc/proto-loader" "^0.7.0"
1436+
"@types/node" ">=12.12.47"
1437+
14381438
"@grpc/proto-loader@^0.7.0":
14391439
version "0.7.2"
14401440
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.2.tgz#fa63178853afe1473c50cff89fe572f7c8b20154"
@@ -3470,7 +3470,7 @@
34703470
"@typescript-eslint/types" "4.33.0"
34713471
eslint-visitor-keys "^2.0.0"
34723472

3473-
"@useorbital/client-types@^1.5.0":
3473+
"@useorbital/client-types@^1.6.0":
34743474
version "1.6.0"
34753475
resolved "https://registry.yarnpkg.com/@useorbital/client-types/-/client-types-1.6.0.tgz#5ae0828964cb50962395b142578ec4c2c39806e8"
34763476
integrity sha512-Lf490y3x1v8jFgEULuLRt7TmN/kSZeQ0hYS4Y6AfHijB6oBp/B0o1MWNrF11KqKY6ghs1CIZi5RxVOXsnd/geQ==

0 commit comments

Comments
 (0)