@teamkeel/functions-runtime 0.299.0 → 0.300.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamkeel/functions-runtime",
3
- "version": "0.299.0",
3
+ "version": "0.300.1",
4
4
  "description": "Internal package used by @teamkeel/sdk",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -47,6 +47,7 @@ async function handleRequest(request, config) {
47
47
  const result = await db.transaction().execute(async (transaction) => {
48
48
  const ctx = createContextAPI(request.meta);
49
49
  const api = createFunctionAPI({
50
+ meta: request.meta,
50
51
  headers,
51
52
  db: transaction,
52
53
  });
@@ -56,7 +57,7 @@ async function handleRequest(request, config) {
56
57
  // Call the user's custom function!
57
58
  const fnResult = await customFunction(request.params, api, ctx);
58
59
 
59
- // api.permissions maintains an internal state of whether the current operation has been *explicitly* permitted/denied by the user in the course of their custom function.
60
+ // api.permissions maintains an internal state of whether the current operation has been *explicitly* permitted/denied by the user in the course of their custom function, or if execution has already been permitted by a role based permission (evaluated in the main runtime).
60
61
  // we need to check that the final state is permitted or unpermitted. if it's not, then it means that the user has taken no explicit action to permit/deny
61
62
  // and therefore we default to checking the permissions defined in the schema automatically.
62
63
  switch (api.permissions.getState()) {
@@ -140,6 +140,40 @@ test("when there is an unexpected error in the custom function", async () => {
140
140
  });
141
141
  });
142
142
 
143
+ test("when a role based permission has already been granted by the main runtime", async () => {
144
+ const config = {
145
+ functions: {
146
+ createPost: async (inputs, api, ctx) => {
147
+ return {
148
+ title: inputs.title,
149
+ };
150
+ },
151
+ },
152
+ actionTypes: {
153
+ createPost: PROTO_ACTION_TYPES.CREATE,
154
+ },
155
+ createFunctionAPI: ({ headers, db }) => {
156
+ return {
157
+ permissions: new Permissions({ status: "granted", reason: "role" }),
158
+ };
159
+ },
160
+ createContextAPI: () => {},
161
+ };
162
+
163
+ const rpcReq = createJSONRPCRequest("123", "createPost", { title: "a post" });
164
+
165
+ expect(await handleRequest(rpcReq, config)).toEqual({
166
+ id: "123",
167
+ jsonrpc: "2.0",
168
+ result: {
169
+ title: "a post",
170
+ },
171
+ meta: {
172
+ headers: {},
173
+ },
174
+ });
175
+ });
176
+
143
177
  test("when there is an unexpected object thrown in the custom function", async () => {
144
178
  const config = {
145
179
  functions: {
@@ -6,12 +6,23 @@ const PERMISSION_STATE = {
6
6
  UNPERMITTED: "unpermitted",
7
7
  };
8
8
 
9
+ const defaultState = {
10
+ status: "unknown",
11
+ };
12
+
9
13
  class Permissions {
10
- constructor() {
14
+ // The permissionState here is the prior state passed in from the Go runtime
15
+ // The Go runtime performs role based permission rule checks prior to calling the functions
16
+ // runtime, so the status could already be granted. If already granted, then we need to inherit that permission state as the state is later used to decide whether to run in process permission checks
17
+ // TLDR if a role based permission is relevant and it is granted, then it is effectively the same as the end user calling api.permissions.allow() explicitly in terms of behaviour.
18
+ constructor(permissionState = defaultState) {
11
19
  this.state = {
12
20
  // permitted starts off as null to indicate that the end user
13
21
  // hasn't explicitly marked a function execution as permitted yet
14
- permitted: null,
22
+ permitted:
23
+ permissionState !== null && permissionState.status === "granted"
24
+ ? true
25
+ : null,
15
26
  };
16
27
  }
17
28
 
@@ -14,10 +14,13 @@ process.env.KEEL_DB_CONN = `postgresql://postgres:postgres@localhost:5432/functi
14
14
  let permissions;
15
15
  let ctx = {};
16
16
  let db = getDatabase();
17
+ let permissionState = {
18
+ status: "unknown",
19
+ };
17
20
 
18
21
  describe("explicit", () => {
19
22
  beforeEach(() => {
20
- permissions = new Permissions();
23
+ permissions = new Permissions(permissionState);
21
24
  });
22
25
 
23
26
  test("explicitly allowing execution", () => {
@@ -37,6 +40,25 @@ describe("explicit", () => {
37
40
  });
38
41
  });
39
42
 
43
+ describe("prior state", () => {
44
+ test("when the prior state is unknown", () => {
45
+ permissions = new Permissions({
46
+ status: "unknown",
47
+ });
48
+
49
+ expect(permissions.getState()).toEqual(PERMISSION_STATE.UNKNOWN);
50
+ });
51
+
52
+ test("when the prior state is granted", () => {
53
+ permissions = new Permissions({
54
+ status: "granted",
55
+ reason: "role",
56
+ });
57
+
58
+ expect(permissions.getState()).toEqual(PERMISSION_STATE.PERMITTED);
59
+ });
60
+ });
61
+
40
62
  describe("check", () => {
41
63
  const functionName = "createPerson";
42
64