@kuadrant/kuadrant-backstage-plugin-backend 0.0.2-dev-39963ad → 0.0.2-dev-30af554

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.
@@ -21,17 +21,19 @@ var cors__default = /*#__PURE__*/_interopDefaultCompat(cors);
21
21
  function generateApiKey() {
22
22
  return crypto.randomBytes(32).toString("hex");
23
23
  }
24
+ function extractNameFromEntityRef(entityRef) {
25
+ const parts = entityRef.split("/");
26
+ return parts[parts.length - 1];
27
+ }
24
28
  async function getUserIdentity(req, httpAuth, userInfo) {
25
29
  const credentials = await httpAuth.credentials(req);
26
30
  if (!credentials || !credentials.principal) {
27
31
  throw new errors.NotAllowedError("authentication required");
28
32
  }
29
33
  const info = await userInfo.getUserInfo(credentials);
30
- const userId = info.userEntityRef.split("/")[1];
31
34
  const groups = info.ownershipEntityRefs || [];
32
- console.log(`user identity resolved: userId=${userId}, userEntityRef=${info.userEntityRef}, groups=${groups.join(",")}`);
35
+ console.log(`user identity resolved: userEntityRef=${info.userEntityRef}, groups=${groups.join(",")}`);
33
36
  return {
34
- userId,
35
37
  userEntityRef: info.userEntityRef,
36
38
  groups
37
39
  };
@@ -52,15 +54,35 @@ async function createRouter({
52
54
  router.get("/apiproducts", async (req, res) => {
53
55
  try {
54
56
  const credentials = await httpAuth.credentials(req);
55
- const decision = await permissions$1.authorize(
57
+ const listDecision = await permissions$1.authorize(
56
58
  [{ permission: permissions.kuadrantApiProductListPermission }],
57
59
  { credentials }
58
60
  );
59
- if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
61
+ if (listDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
60
62
  throw new errors.NotAllowedError("unauthorised");
61
63
  }
64
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
62
65
  const data = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apiproducts");
63
- res.json(data);
66
+ const readAllDecision = await permissions$1.authorize(
67
+ [{ permission: permissions.kuadrantApiProductReadAllPermission }],
68
+ { credentials }
69
+ );
70
+ if (readAllDecision[0].result === pluginPermissionCommon.AuthorizeResult.ALLOW) {
71
+ res.json(data);
72
+ } else {
73
+ const readOwnDecision = await permissions$1.authorize(
74
+ [{ permission: permissions.kuadrantApiProductReadOwnPermission }],
75
+ { credentials }
76
+ );
77
+ if (readOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
78
+ throw new errors.NotAllowedError("unauthorised");
79
+ }
80
+ const ownedItems = (data.items || []).filter((item) => {
81
+ const owner = item.metadata?.annotations?.["backstage.io/owner"];
82
+ return owner === userEntityRef;
83
+ });
84
+ res.json({ ...data, items: ownedItems });
85
+ }
64
86
  } catch (error) {
65
87
  console.error("error fetching apiproducts:", error);
66
88
  if (error instanceof errors.NotAllowedError) {
@@ -73,16 +95,30 @@ async function createRouter({
73
95
  router.get("/apiproducts/:namespace/:name", async (req, res) => {
74
96
  try {
75
97
  const credentials = await httpAuth.credentials(req);
76
- const decision = await permissions$1.authorize(
77
- [{ permission: permissions.kuadrantApiProductReadPermission }],
98
+ const { namespace, name } = req.params;
99
+ const readAllDecision = await permissions$1.authorize(
100
+ [{ permission: permissions.kuadrantApiProductReadAllPermission }],
78
101
  { credentials }
79
102
  );
80
- if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
81
- throw new errors.NotAllowedError("unauthorised");
103
+ if (readAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
104
+ const readOwnDecision = await permissions$1.authorize(
105
+ [{ permission: permissions.kuadrantApiProductReadOwnPermission }],
106
+ { credentials }
107
+ );
108
+ if (readOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
109
+ throw new errors.NotAllowedError("unauthorised");
110
+ }
111
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
112
+ const data = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
113
+ const owner = data.metadata?.annotations?.["backstage.io/owner"];
114
+ if (owner !== userEntityRef) {
115
+ throw new errors.NotAllowedError("you can only read your own api products");
116
+ }
117
+ res.json(data);
118
+ } else {
119
+ const data = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
120
+ res.json(data);
82
121
  }
83
- const { namespace, name } = req.params;
84
- const data = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
85
- res.json(data);
86
122
  } catch (error) {
87
123
  console.error("error fetching apiproduct:", error);
88
124
  if (error instanceof errors.NotAllowedError) {
@@ -102,7 +138,7 @@ async function createRouter({
102
138
  if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
103
139
  throw new errors.NotAllowedError("unauthorised");
104
140
  }
105
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
141
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
106
142
  const apiProduct = req.body;
107
143
  const targetRef = apiProduct.spec?.targetRef;
108
144
  if (!targetRef?.name || !targetRef?.kind || !targetRef?.namespace) {
@@ -110,10 +146,10 @@ async function createRouter({
110
146
  }
111
147
  const namespace = targetRef.namespace;
112
148
  apiProduct.metadata.namespace = namespace;
113
- if (!apiProduct.spec.contact) {
114
- apiProduct.spec.contact = {};
149
+ if (!apiProduct.metadata.annotations) {
150
+ apiProduct.metadata.annotations = {};
115
151
  }
116
- apiProduct.spec.contact.team = `user:default/${userId}`;
152
+ apiProduct.metadata.annotations["backstage.io/owner"] = userEntityRef;
117
153
  const httpRouteNamespace = namespace;
118
154
  const httpRouteName = targetRef.name;
119
155
  try {
@@ -167,14 +203,26 @@ async function createRouter({
167
203
  router.delete("/apiproducts/:namespace/:name", async (req, res) => {
168
204
  try {
169
205
  const credentials = await httpAuth.credentials(req);
170
- const decision = await permissions$1.authorize(
171
- [{ permission: permissions.kuadrantApiProductDeletePermission }],
206
+ const { namespace, name } = req.params;
207
+ const deleteAllDecision = await permissions$1.authorize(
208
+ [{ permission: permissions.kuadrantApiProductDeleteAllPermission }],
172
209
  { credentials }
173
210
  );
174
- if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
175
- throw new errors.NotAllowedError("unauthorised");
211
+ if (deleteAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
212
+ const deleteOwnDecision = await permissions$1.authorize(
213
+ [{ permission: permissions.kuadrantApiProductDeleteOwnPermission }],
214
+ { credentials }
215
+ );
216
+ if (deleteOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
217
+ throw new errors.NotAllowedError("unauthorised");
218
+ }
219
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
220
+ const existing = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
221
+ const owner = existing.metadata?.annotations?.["backstage.io/owner"];
222
+ if (owner !== userEntityRef) {
223
+ throw new errors.NotAllowedError("you can only delete your own api products");
224
+ }
176
225
  }
177
- const { namespace, name } = req.params;
178
226
  await k8sClient$1.deleteCustomResource(
179
227
  "extensions.kuadrant.io",
180
228
  "v1alpha1",
@@ -246,14 +294,29 @@ async function createRouter({
246
294
  if (!credentials || !credentials.principal) {
247
295
  throw new errors.NotAllowedError("authentication required");
248
296
  }
249
- const decision = await permissions$1.authorize(
250
- [{ permission: permissions.kuadrantApiProductUpdatePermission }],
297
+ const { namespace, name } = req.params;
298
+ const updateAllDecision = await permissions$1.authorize(
299
+ [{ permission: permissions.kuadrantApiProductUpdateAllPermission }],
251
300
  { credentials }
252
301
  );
253
- if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
254
- throw new errors.NotAllowedError("unauthorised");
302
+ if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
303
+ const updateOwnDecision = await permissions$1.authorize(
304
+ [{ permission: permissions.kuadrantApiProductUpdateOwnPermission }],
305
+ { credentials }
306
+ );
307
+ if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
308
+ throw new errors.NotAllowedError("unauthorised");
309
+ }
310
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
311
+ const existing = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
312
+ const owner = existing.metadata?.annotations?.["backstage.io/owner"];
313
+ if (owner !== userEntityRef) {
314
+ throw new errors.NotAllowedError("you can only update your own api products");
315
+ }
316
+ }
317
+ if (req.body.metadata?.annotations) {
318
+ delete req.body.metadata.annotations["backstage.io/owner"];
255
319
  }
256
- const { namespace, name } = req.params;
257
320
  const updated = await k8sClient$1.patchCustomResource(
258
321
  "extensions.kuadrant.io",
259
322
  "v1alpha1",
@@ -353,7 +416,7 @@ async function createRouter({
353
416
  try {
354
417
  const credentials = await httpAuth.credentials(req);
355
418
  const { apiName, apiNamespace, planTier, useCase, userEmail } = parsed.data;
356
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
419
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
357
420
  const resourceRef = `apiproduct:${apiNamespace}/${apiName}`;
358
421
  const decision = await permissions$1.authorize(
359
422
  [{
@@ -367,8 +430,9 @@ async function createRouter({
367
430
  }
368
431
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
369
432
  const randomSuffix = crypto.randomBytes(4).toString("hex");
370
- const requestName = `${userId}-${apiName}-${randomSuffix}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
371
- const requestedBy = { userId };
433
+ const userName = extractNameFromEntityRef(userEntityRef);
434
+ const requestName = `${userName}-${apiName}-${randomSuffix}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
435
+ const requestedBy = { userId: userEntityRef };
372
436
  if (userEmail) {
373
437
  requestedBy.email = userEmail;
374
438
  }
@@ -406,7 +470,8 @@ async function createRouter({
406
470
  if (apiProduct.spec?.approvalMode === "automatic") {
407
471
  const apiKey = generateApiKey();
408
472
  const timestamp2 = Date.now();
409
- const secretName = `${userId}-${apiName}-${timestamp2}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
473
+ const userName2 = extractNameFromEntityRef(userEntityRef);
474
+ const secretName = `${userName2}-${apiName}-${timestamp2}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
410
475
  const secret = {
411
476
  apiVersion: "v1",
412
477
  kind: "Secret",
@@ -418,7 +483,7 @@ async function createRouter({
418
483
  },
419
484
  annotations: {
420
485
  "secret.kuadrant.io/plan-id": planTier,
421
- "secret.kuadrant.io/user-id": userId
486
+ "secret.kuadrant.io/user-id": userEntityRef
422
487
  }
423
488
  },
424
489
  stringData: {
@@ -483,12 +548,19 @@ async function createRouter({
483
548
  router.get("/requests", async (req, res) => {
484
549
  try {
485
550
  const credentials = await httpAuth.credentials(req);
486
- const decision = await permissions$1.authorize(
487
- [{ permission: permissions.kuadrantApiKeyRequestListPermission }],
551
+ const readAllDecision = await permissions$1.authorize(
552
+ [{ permission: permissions.kuadrantApiKeyRequestReadAllPermission }],
488
553
  { credentials }
489
554
  );
490
- if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
491
- throw new errors.NotAllowedError("unauthorised");
555
+ const canReadAll = readAllDecision[0].result === pluginPermissionCommon.AuthorizeResult.ALLOW;
556
+ if (!canReadAll) {
557
+ const readOwnDecision = await permissions$1.authorize(
558
+ [{ permission: permissions.kuadrantApiKeyRequestReadOwnPermission }],
559
+ { credentials }
560
+ );
561
+ if (readOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
562
+ throw new errors.NotAllowedError("unauthorised");
563
+ }
492
564
  }
493
565
  const status = req.query.status;
494
566
  const namespace = req.query.namespace;
@@ -499,6 +571,17 @@ async function createRouter({
499
571
  data = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apikeyrequests");
500
572
  }
501
573
  let filteredItems = data.items || [];
574
+ if (!canReadAll) {
575
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
576
+ const apiproducts = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apiproducts");
577
+ const ownedApiProducts = (apiproducts.items || []).filter((product) => {
578
+ const owner = product.metadata?.annotations?.["backstage.io/owner"];
579
+ return owner === userEntityRef;
580
+ }).map((product) => product.metadata.name);
581
+ filteredItems = filteredItems.filter(
582
+ (req2) => ownedApiProducts.includes(req2.spec?.apiName)
583
+ );
584
+ }
502
585
  if (status) {
503
586
  filteredItems = filteredItems.filter((req2) => {
504
587
  const phase = req2.status?.phase || "Pending";
@@ -525,7 +608,7 @@ async function createRouter({
525
608
  if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
526
609
  throw new errors.NotAllowedError("unauthorised");
527
610
  }
528
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
611
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
529
612
  const namespace = req.query.namespace;
530
613
  let data;
531
614
  if (namespace) {
@@ -534,7 +617,7 @@ async function createRouter({
534
617
  data = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apikeyrequests");
535
618
  }
536
619
  const filteredItems = (data.items || []).filter(
537
- (req2) => req2.spec?.requestedBy?.userId === userId
620
+ (req2) => req2.spec?.requestedBy?.userId === userEntityRef
538
621
  );
539
622
  res.json({ items: filteredItems });
540
623
  } catch (error) {
@@ -556,17 +639,10 @@ async function createRouter({
556
639
  }
557
640
  try {
558
641
  const credentials = await httpAuth.credentials(req);
559
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
560
- const decision = await permissions$1.authorize(
561
- [{ permission: permissions.kuadrantApiKeyRequestUpdatePermission }],
562
- { credentials }
563
- );
564
- if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
565
- throw new errors.NotAllowedError("unauthorised");
566
- }
642
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
567
643
  const { namespace, name } = req.params;
568
644
  const { comment } = parsed.data;
569
- const reviewedBy = `user:default/${userId}`;
645
+ const reviewedBy = userEntityRef;
570
646
  const request = await k8sClient$1.getCustomResource(
571
647
  "extensions.kuadrant.io",
572
648
  "v1alpha1",
@@ -575,9 +651,34 @@ async function createRouter({
575
651
  name
576
652
  );
577
653
  const spec = request.spec;
654
+ const apiProduct = await k8sClient$1.getCustomResource(
655
+ "extensions.kuadrant.io",
656
+ "v1alpha1",
657
+ spec.apiNamespace,
658
+ "apiproducts",
659
+ spec.apiName
660
+ );
661
+ const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
662
+ const updateAllDecision = await permissions$1.authorize(
663
+ [{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
664
+ { credentials }
665
+ );
666
+ if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
667
+ const updateOwnDecision = await permissions$1.authorize(
668
+ [{ permission: permissions.kuadrantApiKeyRequestUpdateOwnPermission }],
669
+ { credentials }
670
+ );
671
+ if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
672
+ throw new errors.NotAllowedError("unauthorised");
673
+ }
674
+ if (owner !== userEntityRef) {
675
+ throw new errors.NotAllowedError("you can only approve requests for your own api products");
676
+ }
677
+ }
578
678
  const apiKey = generateApiKey();
579
679
  const timestamp = Date.now();
580
- const secretName = `${spec.requestedBy.userId}-${spec.apiName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
680
+ const userName = extractNameFromEntityRef(spec.requestedBy.userId);
681
+ const secretName = `${userName}-${spec.apiName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
581
682
  const secret = {
582
683
  apiVersion: "v1",
583
684
  kind: "Secret",
@@ -681,17 +782,42 @@ async function createRouter({
681
782
  }
682
783
  try {
683
784
  const credentials = await httpAuth.credentials(req);
684
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
685
- const decision = await permissions$1.authorize(
686
- [{ permission: permissions.kuadrantApiKeyRequestUpdatePermission }],
785
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
786
+ const { namespace, name } = req.params;
787
+ const { comment } = parsed.data;
788
+ const reviewedBy = userEntityRef;
789
+ const request = await k8sClient$1.getCustomResource(
790
+ "extensions.kuadrant.io",
791
+ "v1alpha1",
792
+ namespace,
793
+ "apikeyrequests",
794
+ name
795
+ );
796
+ const spec = request.spec;
797
+ const apiProduct = await k8sClient$1.getCustomResource(
798
+ "extensions.kuadrant.io",
799
+ "v1alpha1",
800
+ spec.apiNamespace,
801
+ "apiproducts",
802
+ spec.apiName
803
+ );
804
+ const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
805
+ const updateAllDecision = await permissions$1.authorize(
806
+ [{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
687
807
  { credentials }
688
808
  );
689
- if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
690
- throw new errors.NotAllowedError("unauthorised");
809
+ if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
810
+ const updateOwnDecision = await permissions$1.authorize(
811
+ [{ permission: permissions.kuadrantApiKeyRequestUpdateOwnPermission }],
812
+ { credentials }
813
+ );
814
+ if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
815
+ throw new errors.NotAllowedError("unauthorised");
816
+ }
817
+ if (owner !== userEntityRef) {
818
+ throw new errors.NotAllowedError("you can only reject requests for your own api products");
819
+ }
691
820
  }
692
- const { namespace, name } = req.params;
693
- const { comment } = parsed.data;
694
- const reviewedBy = `user:default/${userId}`;
695
821
  const status = {
696
822
  phase: "Rejected",
697
823
  reviewedBy,
@@ -730,16 +856,16 @@ async function createRouter({
730
856
  }
731
857
  try {
732
858
  const credentials = await httpAuth.credentials(req);
733
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
859
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
734
860
  const decision = await permissions$1.authorize(
735
- [{ permission: permissions.kuadrantApiKeyRequestUpdatePermission }],
861
+ [{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
736
862
  { credentials }
737
863
  );
738
864
  if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
739
865
  throw new errors.NotAllowedError("unauthorised");
740
866
  }
741
867
  const { requests, comment } = parsed.data;
742
- const reviewedBy = `user:default/${userId}`;
868
+ const reviewedBy = userEntityRef;
743
869
  const results = [];
744
870
  for (const reqRef of requests) {
745
871
  try {
@@ -751,9 +877,34 @@ async function createRouter({
751
877
  reqRef.name
752
878
  );
753
879
  const spec = request.spec;
880
+ const apiProduct = await k8sClient$1.getCustomResource(
881
+ "extensions.kuadrant.io",
882
+ "v1alpha1",
883
+ spec.apiNamespace,
884
+ "apiproducts",
885
+ spec.apiName
886
+ );
887
+ const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
888
+ const updateAllDecision = await permissions$1.authorize(
889
+ [{ permission: permissions.kuadrantApiProductUpdateAllPermission }],
890
+ { credentials }
891
+ );
892
+ if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
893
+ const updateOwnDecision = await permissions$1.authorize(
894
+ [{ permission: permissions.kuadrantApiProductUpdateOwnPermission }],
895
+ { credentials }
896
+ );
897
+ if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
898
+ throw new errors.NotAllowedError("unauthorised");
899
+ }
900
+ if (owner !== userEntityRef) {
901
+ throw new errors.NotAllowedError("you can only approve requests for your own api products");
902
+ }
903
+ }
754
904
  const apiKey = generateApiKey();
755
905
  const timestamp = Date.now();
756
- const secretName = `${spec.requestedBy.userId}-${spec.apiName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
906
+ const userName = extractNameFromEntityRef(spec.requestedBy.userId);
907
+ const secretName = `${userName}-${spec.apiName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
757
908
  const secret = {
758
909
  apiVersion: "v1",
759
910
  kind: "Secret",
@@ -868,19 +1019,51 @@ async function createRouter({
868
1019
  }
869
1020
  try {
870
1021
  const credentials = await httpAuth.credentials(req);
871
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
1022
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
872
1023
  const decision = await permissions$1.authorize(
873
- [{ permission: permissions.kuadrantApiKeyRequestUpdatePermission }],
1024
+ [{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
874
1025
  { credentials }
875
1026
  );
876
1027
  if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
877
1028
  throw new errors.NotAllowedError("unauthorised");
878
1029
  }
879
1030
  const { requests, comment } = parsed.data;
880
- const reviewedBy = `user:default/${userId}`;
1031
+ const reviewedBy = userEntityRef;
881
1032
  const results = [];
882
1033
  for (const reqRef of requests) {
883
1034
  try {
1035
+ const request = await k8sClient$1.getCustomResource(
1036
+ "extensions.kuadrant.io",
1037
+ "v1alpha1",
1038
+ reqRef.namespace,
1039
+ "apikeyrequests",
1040
+ reqRef.name
1041
+ );
1042
+ const spec = request.spec;
1043
+ const apiProduct = await k8sClient$1.getCustomResource(
1044
+ "extensions.kuadrant.io",
1045
+ "v1alpha1",
1046
+ spec.apiNamespace,
1047
+ "apiproducts",
1048
+ spec.apiName
1049
+ );
1050
+ const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
1051
+ const updateAllDecision = await permissions$1.authorize(
1052
+ [{ permission: permissions.kuadrantApiProductUpdateAllPermission }],
1053
+ { credentials }
1054
+ );
1055
+ if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
1056
+ const updateOwnDecision = await permissions$1.authorize(
1057
+ [{ permission: permissions.kuadrantApiProductUpdateOwnPermission }],
1058
+ { credentials }
1059
+ );
1060
+ if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
1061
+ throw new errors.NotAllowedError("unauthorised");
1062
+ }
1063
+ if (owner !== userEntityRef) {
1064
+ throw new errors.NotAllowedError("you can only reject requests for your own api products");
1065
+ }
1066
+ }
884
1067
  const status = {
885
1068
  phase: "Rejected",
886
1069
  reviewedBy,
@@ -919,7 +1102,7 @@ async function createRouter({
919
1102
  router.delete("/requests/:namespace/:name", async (req, res) => {
920
1103
  try {
921
1104
  const credentials = await httpAuth.credentials(req);
922
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
1105
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
923
1106
  const { namespace, name } = req.params;
924
1107
  const request = await k8sClient$1.getCustomResource(
925
1108
  "extensions.kuadrant.io",
@@ -942,7 +1125,7 @@ async function createRouter({
942
1125
  if (deleteOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
943
1126
  throw new errors.NotAllowedError("unauthorised");
944
1127
  }
945
- if (requestUserId !== userId) {
1128
+ if (requestUserId !== userEntityRef) {
946
1129
  throw new errors.NotAllowedError("you can only delete your own api key requests");
947
1130
  }
948
1131
  }
@@ -983,7 +1166,8 @@ async function createRouter({
983
1166
  router.patch("/requests/:namespace/:name", async (req, res) => {
984
1167
  const patchSchema = zod.z.object({
985
1168
  spec: zod.z.object({
986
- useCase: zod.z.string().optional()
1169
+ useCase: zod.z.string().optional(),
1170
+ planTier: zod.z.string().optional()
987
1171
  }).partial()
988
1172
  });
989
1173
  const parsed = patchSchema.safeParse(req.body);
@@ -992,7 +1176,7 @@ async function createRouter({
992
1176
  }
993
1177
  try {
994
1178
  const credentials = await httpAuth.credentials(req);
995
- const { userId } = await getUserIdentity(req, httpAuth, userInfo);
1179
+ const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
996
1180
  const { namespace, name } = req.params;
997
1181
  const existing = await k8sClient$1.getCustomResource(
998
1182
  "extensions.kuadrant.io",
@@ -1001,8 +1185,13 @@ async function createRouter({
1001
1185
  "apikeyrequests",
1002
1186
  name
1003
1187
  );
1188
+ const requestUserId = existing.spec?.requestedBy?.userId;
1189
+ const currentPhase = existing.status?.phase || "Pending";
1190
+ if (currentPhase !== "Pending") {
1191
+ throw new errors.NotAllowedError("only pending requests can be edited");
1192
+ }
1004
1193
  const updateAllDecision = await permissions$1.authorize(
1005
- [{ permission: permissions.kuadrantApiKeyRequestUpdatePermission }],
1194
+ [{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
1006
1195
  { credentials }
1007
1196
  );
1008
1197
  if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
@@ -1013,7 +1202,7 @@ async function createRouter({
1013
1202
  if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
1014
1203
  throw new errors.NotAllowedError("unauthorised");
1015
1204
  }
1016
- if (existing.spec?.requestedBy?.userId !== userId) {
1205
+ if (requestUserId !== userEntityRef) {
1017
1206
  throw new errors.NotAllowedError("you can only update your own api key requests");
1018
1207
  }
1019
1208
  }