@backstage-community/plugin-mend-backend 0.10.0 → 1.1.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,82 @@
1
1
  # @backstage-community/plugin-mend-backend
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 93f75d2: Backstage version bump to v1.48.2
8
+
9
+ ## 1.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - bc3cc34: - Updated Frontend system to provide the Backstage Portal Support
14
+
15
+ - **BREAKING** The permission-policy-based project filtering has been removed in favor of configuration-based `mend.permissionControl`. This is only applicable if you previously used the Mend permissions in your `PermissionPolicy` to control which project IDs are visible.
16
+
17
+ Previously, you might have configured project filtering like this in your organization policy:
18
+
19
+ ```ts
20
+ // ... other imports here
21
+ import {
22
+ mendReadPermission,
23
+ mendConditions,
24
+ createMendProjectConditionalDecision,
25
+ } from '@backstage-community/plugin-mend-backend';
26
+
27
+ export class OrganizationPolicy implements PermissionPolicy {
28
+ async handle(
29
+ request: PolicyQuery,
30
+ user?: BackstageIdentityResponse,
31
+ ): Promise<PolicyDecision> {
32
+ if (isPermission(request.permission, mendReadPermission)) {
33
+ return createMendProjectConditionalDecision(
34
+ request.permission,
35
+ mendConditions.filter({
36
+ ids: [], // List of project ids
37
+ exclude: true, // Default
38
+ }),
39
+ );
40
+ }
41
+
42
+ // ... other conditions
43
+ return {
44
+ result: AuthorizeResult.ALLOW,
45
+ };
46
+ }
47
+ }
48
+ ```
49
+
50
+ You must now configure the equivalent behavior via `app-config.yaml`:
51
+
52
+ ```yaml
53
+ mend:
54
+ activationKey: ${MEND_ACTIVATION_KEY}
55
+ permissionControl:
56
+ ids:
57
+ - <project-uuid-1> # Project UUID to filter
58
+ - <project-uuid-2> # Another project UUID
59
+ exclude: true # true = blocklist (exclude these), false = allowlist (only these)
60
+ ```
61
+
62
+ Migration steps:
63
+
64
+ 1. Copy the same `ids` list and `exclude` value you used in your permission policy into the `mend.permissionControl` configuration in `app-config.yaml`.
65
+ 2. Remove the permission-related code (such as `mendReadPermission`, `mendConditions`, and `createMendProjectConditionalDecision` usage) from your custom permission policy file (for example, `packages/backend/src/plugins/permission.ts`).
66
+ 3. Remove the Mend permission imports from `packages/backend/src/index.ts` and ensure your default policy continues to allow access (for example, by using an allow-all-policy if no other policy is defined).
67
+
68
+ ```diff
69
+ backend.add(import('@backstage/plugin-permission-backend'));
70
+ + backend.add(
71
+ + import('@backstage/plugin-permission-backend-module-allow-all-policy'),
72
+ + );
73
+ - backend.add(import('./plugins/permission'));
74
+ ```
75
+
76
+ ### Patch Changes
77
+
78
+ - b133c9d: Updated dependency `@types/supertest` to `^6.0.0`.
79
+
3
80
  ## 0.10.0
4
81
 
5
82
  ### Minor Changes
package/README.md CHANGED
@@ -9,46 +9,34 @@ In your `packages/backend/src/index.ts` file:
9
9
  backend.add(import('@backstage-community/plugin-mend-backend'));
10
10
  ```
11
11
 
12
- ### Plugin Permission (optional)
12
+ ### Permission Control (optional)
13
13
 
14
- The plugin offers methods to construct conditional permissions an additional top layer to filter projects, which can be integrated into the your Organization Permission Policy.
14
+ The plugin supports configuration-based permission control to filter which projects are visible to users.
15
15
 
16
- - Provide a list of project IDs to the plugin. This will enable it to filter projects.
17
- - Use the `exclude` property to fine-tune the filtering behavior, ensuring precise control over which projects are included or excluded from the permission set.
16
+ - Provide a list of project IDs in the configuration to filter projects.
17
+ - Use the `exclude` property to control the filtering behavior:
18
+ - `true` (blocklist mode): Show all projects EXCEPT those in the list
19
+ - `false` (allowlist mode): Show ONLY projects in the list
18
20
 
19
- Here is a sample:
21
+ Add the following configuration to your `app-config.yaml`:
20
22
 
21
- ```ts
22
- // ... other imports here
23
- import {
24
- mendReadPermission,
25
- mendConditions,
26
- createMendProjectConditionalDecision,
27
- } from '@backstage-community/plugin-mend-backend';
28
- // ... other polices
29
- export class OrganizationPolicy implements PermissionPolicy {
30
- async handle(
31
- request: PolicyQuery,
32
- user?: BackstageIdentityResponse,
33
- ): Promise<PolicyDecision> {
34
- if (isPermission(request.permission, mendReadPermission)) {
35
- return createMendProjectConditionalDecision(
36
- request.permission,
37
- mendConditions.filter({
38
- ids: [], // List of project id
39
- exclude: true, // Default
40
- }),
41
- );
42
- }
43
- // ... other conditions
44
- return {
45
- result: AuthorizeResult.ALLOW,
46
- };
47
- }
48
- }
49
- // ...
23
+ ```yaml
24
+ mend:
25
+ activationKey: ${MEND_ACTIVATION_KEY}
26
+ permissionControl:
27
+ ids:
28
+ - <project-uuid-1> # Project UUID to filter
29
+ - <project-uuid-2> # Another project UUID
30
+ exclude: true # Set to true for blocklist mode, false for allowlist mode
50
31
  ```
51
32
 
33
+ **Configuration Options:**
34
+
35
+ - `ids`: Array of project UUIDs to include or exclude
36
+ - `exclude`: Boolean flag (default: `true`)
37
+ - `true`: Exclude the listed projects (blocklist)
38
+ - `false`: Only show the listed projects (allowlist)
39
+
52
40
  **Add the Mend.io frontend plugin**
53
41
 
54
42
  See the [mend frontend plugin instructions](../mend/README.md).
package/config.d.ts CHANGED
@@ -1,8 +1,44 @@
1
+ /*
2
+ * Copyright 2025 The Backstage Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
1
16
  export type Config = {
2
- mend: {
17
+ mend?: {
3
18
  /**
4
19
  * @visibility secret
5
20
  */
6
21
  activationKey: string;
22
+
23
+ /**
24
+ * Permission control configuration for entity access.
25
+ * Controls which entities users can view Apiiro data for.
26
+ * @visibility frontend
27
+ */
28
+ permissionControl?: {
29
+ /**
30
+ * List of project ids for that you want the permission control
31
+ */
32
+ ids: string[];
33
+
34
+ /**
35
+ * Determines the permission control mode:
36
+ * - true (blocklist mode): Allow all project ids EXCEPT those listed in ids
37
+ * - false (allowlist mode): Deny all project ids EXCEPT those listed in ids
38
+ *
39
+ * @default true
40
+ */
41
+ exclude?: boolean;
42
+ };
7
43
  };
8
44
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../../src/api/index.ts"],"sourcesContent":["import { MendAuthSevice } from '../service/auth.service';\n\nexport type QueryParams = Record<string, string>;\n\ntype RequestHeaders = Record<string, string>;\n\nenum ApiHeaders {\n AUTH_TOKEN = 'Authorization',\n CONTENT_TYPE = 'Content-Type',\n AGENT_NAME = 'agent-name',\n AGENT_VERSION = 'agent-version',\n}\n\nenum REQUEST_METHOD {\n GET = 'GET',\n POST = 'POST',\n PUT = 'PUT',\n DELETE = 'DELETE',\n}\n\ninterface RequestOptions {\n body?: any;\n headers?: RequestHeaders;\n params?: Record<string, any> | null;\n}\n\nfunction assembleUri(uri: string, params?: QueryParams): string {\n if (!params) {\n return uri;\n }\n\n const queryString = new URLSearchParams(params).toString();\n return `${uri}?${queryString}`;\n}\n\nfunction buildHeaders(optionHeaders: RequestHeaders): Headers {\n const headers = new Headers();\n headers.set(ApiHeaders.CONTENT_TYPE, 'application/json');\n headers.set(ApiHeaders.AGENT_NAME, 'pi-backstage');\n headers.set(ApiHeaders.AGENT_VERSION, '24.8.2');\n\n const authToken = MendAuthSevice.getAuthToken();\n\n if (authToken) {\n headers.set(ApiHeaders.AUTH_TOKEN, `Bearer ${authToken}`);\n }\n\n Object.keys(optionHeaders).forEach(header => {\n const headerValue = optionHeaders[header];\n if (headerValue) {\n headers.set(header, headerValue);\n }\n });\n\n return headers;\n}\n\nfunction fetchRequest(\n method: REQUEST_METHOD,\n path: string,\n opts: RequestOptions,\n): Promise<any> {\n return MendAuthSevice.validateAuthToken(path).then(() => {\n const { params, body, headers } = opts;\n\n const url = `${MendAuthSevice.getBaseUrl()}${path}`;\n const requestURL = params ? assembleUri(url, params) : url;\n\n const requestParams = {\n headers: buildHeaders(headers || {}),\n method,\n body,\n };\n\n if (body) {\n requestParams.body =\n typeof body === 'string' ? body : JSON.stringify(body);\n }\n\n const requestObject: Request = new Request(requestURL, requestParams);\n\n return fetch(requestObject);\n });\n}\n\nfunction toJson(response: Response): Promise<any> {\n if (response.status === 204 || response.body === null) {\n return Promise.resolve({});\n }\n\n return response.json().then(json => {\n return response.ok ? json : Promise.reject(response);\n });\n}\n\nconst defaultOpts: RequestOptions = {\n body: null,\n headers: {},\n params: null,\n};\n\nexport function get<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.GET, url, opts).then(toJson);\n}\n\nexport function post<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.POST, url, opts).then(toJson);\n}\n\nexport function put<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.PUT, url, opts).then(toJson);\n}\n\nexport function remove<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.DELETE, url, opts).then(toJson);\n}\n"],"names":["MendAuthSevice"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../../src/api/index.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { MendAuthSevice } from '../service/auth.service';\n\nexport type QueryParams = Record<string, string>;\n\ntype RequestHeaders = Record<string, string>;\n\nenum ApiHeaders {\n AUTH_TOKEN = 'Authorization',\n CONTENT_TYPE = 'Content-Type',\n AGENT_NAME = 'agent-name',\n AGENT_VERSION = 'agent-version',\n}\n\nenum REQUEST_METHOD {\n GET = 'GET',\n POST = 'POST',\n PUT = 'PUT',\n DELETE = 'DELETE',\n}\n\ninterface RequestOptions {\n body?: any;\n headers?: RequestHeaders;\n params?: Record<string, any> | null;\n}\n\nfunction assembleUri(uri: string, params?: QueryParams): string {\n if (!params) {\n return uri;\n }\n\n const queryString = new URLSearchParams(params).toString();\n return `${uri}?${queryString}`;\n}\n\nfunction buildHeaders(optionHeaders: RequestHeaders): Headers {\n const headers = new Headers();\n headers.set(ApiHeaders.CONTENT_TYPE, 'application/json');\n headers.set(ApiHeaders.AGENT_NAME, 'pi-backstage');\n headers.set(ApiHeaders.AGENT_VERSION, '24.8.2');\n\n const authToken = MendAuthSevice.getAuthToken();\n\n if (authToken) {\n headers.set(ApiHeaders.AUTH_TOKEN, `Bearer ${authToken}`);\n }\n\n Object.keys(optionHeaders).forEach(header => {\n const headerValue = optionHeaders[header];\n if (headerValue) {\n headers.set(header, headerValue);\n }\n });\n\n return headers;\n}\n\nfunction fetchRequest(\n method: REQUEST_METHOD,\n path: string,\n opts: RequestOptions,\n): Promise<any> {\n return MendAuthSevice.validateAuthToken(path).then(() => {\n const { params, body, headers } = opts;\n\n const url = `${MendAuthSevice.getBaseUrl()}${path}`;\n const requestURL = params ? assembleUri(url, params) : url;\n\n const requestParams = {\n headers: buildHeaders(headers || {}),\n method,\n body,\n };\n\n if (body) {\n requestParams.body =\n typeof body === 'string' ? body : JSON.stringify(body);\n }\n\n const requestObject: Request = new Request(requestURL, requestParams);\n\n return fetch(requestObject);\n });\n}\n\nfunction toJson(response: Response): Promise<any> {\n if (response.status === 204 || response.body === null) {\n return Promise.resolve({});\n }\n\n return response.json().then(json => {\n return response.ok ? json : Promise.reject(response);\n });\n}\n\nconst defaultOpts: RequestOptions = {\n body: null,\n headers: {},\n params: null,\n};\n\nexport function get<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.GET, url, opts).then(toJson);\n}\n\nexport function post<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.POST, url, opts).then(toJson);\n}\n\nexport function put<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.PUT, url, opts).then(toJson);\n}\n\nexport function remove<T>(\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(REQUEST_METHOD.DELETE, url, opts).then(toJson);\n}\n"],"names":["MendAuthSevice"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"constants.cjs.js","sources":["../src/constants.ts"],"sourcesContent":["// Mend API Version : Update this variable to update the API Version\nexport const MEND_API_VERSION: string = 'v3.0';\n\nexport const AZURE_HOST_NAME: string = 'dev.azure.com';\n"],"names":[],"mappings":";;AACO,MAAM,gBAA2B,GAAA;AAEjC,MAAM,eAA0B,GAAA;;;;;"}
1
+ {"version":3,"file":"constants.cjs.js","sources":["../src/constants.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const MEND_API_VERSION: string = 'v3.0';\n\nexport const AZURE_HOST_NAME: string = 'dev.azure.com';\n"],"names":[],"mappings":";;AAgBO,MAAM,gBAAA,GAA2B;AAEjC,MAAM,eAAA,GAA0B;;;;;"}
package/dist/index.cjs.js CHANGED
@@ -4,16 +4,9 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var router = require('./service/router.cjs.js');
6
6
  var plugin = require('./plugin.cjs.js');
7
- var permissions = require('./permission/permissions.cjs.js');
8
- var conditions = require('./permission/conditions.cjs.js');
9
- require('./permission/rules.cjs.js');
10
7
 
11
8
 
12
9
 
13
10
  exports.createRouter = router.createRouter;
14
11
  exports.default = plugin.mendPlugin;
15
- exports.RESOURCE_TYPE = permissions.RESOURCE_TYPE;
16
- exports.mendReadPermission = permissions.mendReadPermission;
17
- exports.createMendProjectConditionalDecision = conditions.createMendProjectConditionalDecision;
18
- exports.mendConditions = conditions.mendConditions;
19
12
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,4 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
- import * as _backstage_plugin_permission_common from '@backstage/plugin-permission-common';
3
- import * as _backstage_plugin_permission_node from '@backstage/plugin-permission-node';
4
2
 
5
3
  /**
6
4
  * mendPlugin backend plugin
@@ -9,37 +7,4 @@ import * as _backstage_plugin_permission_node from '@backstage/plugin-permission
9
7
  */
10
8
  declare const mendPlugin: _backstage_backend_plugin_api.BackendFeature;
11
9
 
12
- /** @public */
13
- declare enum RESOURCE_TYPE {
14
- PROJECT = "mend-project"
15
- }
16
- /** @public */
17
- declare const mendReadPermission: _backstage_plugin_permission_common.ResourcePermission<RESOURCE_TYPE>;
18
-
19
- /** @public */
20
- type FilterProps = {
21
- ids: string[];
22
- exclude?: boolean;
23
- };
24
-
25
- /** @public */
26
- declare const mendConditions: _backstage_plugin_permission_node.Conditions<{
27
- filter: _backstage_plugin_permission_node.PermissionRule<{
28
- permission: {
29
- type: string;
30
- name: string;
31
- attributes: {
32
- action?: "update" | "read" | "delete" | "create" | undefined;
33
- };
34
- resourceType: RESOURCE_TYPE;
35
- };
36
- resourceRef: string;
37
- }, FilterProps, RESOURCE_TYPE, {
38
- ids: string[];
39
- exclude?: boolean | undefined;
40
- }>;
41
- }>;
42
- /** @public */
43
- declare const createMendProjectConditionalDecision: (permission: _backstage_plugin_permission_common.ResourcePermission<RESOURCE_TYPE>, conditions: _backstage_plugin_permission_common.PermissionCriteria<_backstage_plugin_permission_common.PermissionCondition<RESOURCE_TYPE>>) => _backstage_plugin_permission_common.ConditionalPolicyDecision;
44
-
45
- export { type FilterProps, RESOURCE_TYPE, createMendProjectConditionalDecision, mendPlugin as default, mendConditions, mendReadPermission };
10
+ export { mendPlugin as default };
@@ -13,26 +13,16 @@ const mendPlugin = backendPluginApi.createBackendPlugin({
13
13
  discovery: backendPluginApi.coreServices.discovery,
14
14
  httpAuth: backendPluginApi.coreServices.httpAuth,
15
15
  httpRouter: backendPluginApi.coreServices.httpRouter,
16
- logger: backendPluginApi.coreServices.logger,
17
- permissions: backendPluginApi.coreServices.permissions
16
+ logger: backendPluginApi.coreServices.logger
18
17
  },
19
- async init({
20
- auth,
21
- config,
22
- discovery,
23
- httpAuth,
24
- httpRouter,
25
- logger,
26
- permissions
27
- }) {
18
+ async init({ auth, config, discovery, httpAuth, httpRouter, logger }) {
28
19
  httpRouter.use(
29
20
  await router.createRouter({
30
21
  auth,
31
22
  config,
32
23
  discovery,
33
24
  httpAuth,
34
- logger,
35
- permissions
25
+ logger
36
26
  })
37
27
  );
38
28
  httpRouter.addAuthPolicy({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * mendPlugin backend plugin\n *\n * @public\n */\nexport const mendPlugin = createBackendPlugin({\n pluginId: 'mend',\n register(env) {\n env.registerInit({\n deps: {\n auth: coreServices.auth,\n config: coreServices.rootConfig,\n discovery: coreServices.discovery,\n httpAuth: coreServices.httpAuth,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n permissions: coreServices.permissions,\n },\n async init({\n auth,\n config,\n discovery,\n httpAuth,\n httpRouter,\n logger,\n permissions,\n }) {\n httpRouter.use(\n await createRouter({\n auth,\n config,\n discovery,\n httpAuth,\n logger,\n permissions,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","createRouter"],"mappings":";;;;;AAWO,MAAM,aAAaA,oCAAoB,CAAA;AAAA,EAC5C,QAAU,EAAA,MAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,MAAMC,6BAAa,CAAA,IAAA;AAAA,QACnB,QAAQA,6BAAa,CAAA,UAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,aAAaA,6BAAa,CAAA;AAAA,OAC5B;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,IAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,QAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,IAAA;AAAA,YACA,MAAA;AAAA,YACA,SAAA;AAAA,YACA,QAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA;AAAA,SACR,CAAA;AAAA;AACH,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * mendPlugin backend plugin\n *\n * @public\n */\nexport const mendPlugin = createBackendPlugin({\n pluginId: 'mend',\n register(env) {\n env.registerInit({\n deps: {\n auth: coreServices.auth,\n config: coreServices.rootConfig,\n discovery: coreServices.discovery,\n httpAuth: coreServices.httpAuth,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n },\n async init({ auth, config, discovery, httpAuth, httpRouter, logger }) {\n httpRouter.use(\n await createRouter({\n auth,\n config,\n discovery,\n httpAuth,\n logger,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","createRouter"],"mappings":";;;;;AA0BO,MAAM,aAAaA,oCAAA,CAAoB;AAAA,EAC5C,QAAA,EAAU,MAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,MAAMC,6BAAA,CAAa,IAAA;AAAA,QACnB,QAAQA,6BAAA,CAAa,UAAA;AAAA,QACrB,WAAWA,6BAAA,CAAa,SAAA;AAAA,QACxB,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,YAAYA,6BAAA,CAAa,UAAA;AAAA,QACzB,QAAQA,6BAAA,CAAa;AAAA,OACvB;AAAA,MACA,MAAM,KAAK,EAAE,IAAA,EAAM,QAAQ,SAAA,EAAW,QAAA,EAAU,UAAA,EAAY,MAAA,EAAO,EAAG;AACpE,QAAA,UAAA,CAAW,GAAA;AAAA,UACT,MAAMC,mBAAA,CAAa;AAAA,YACjB,IAAA;AAAA,YACA,MAAA;AAAA,YACA,SAAA;AAAA,YACA,QAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAA,CAAc;AAAA,UACvB,IAAA,EAAM,SAAA;AAAA,UACN,KAAA,EAAO;AAAA,SACR,CAAA;AAAA,MACH;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
@@ -17,30 +17,54 @@ class MendAuthSevice {
17
17
  static clientUrl = "";
18
18
  static clientName = "";
19
19
  static clientUuid = "";
20
+ static configured = false;
21
+ static configurationError = "";
22
+ static logger;
20
23
  constructor(config) {
21
- this.getConfig(config.apiVersion, config.activationKey);
24
+ MendAuthSevice.init(config);
22
25
  }
23
- getConfig(apiVersion, activationKey) {
26
+ static init(config) {
27
+ MendAuthSevice.logger = config.logger;
28
+ MendAuthSevice.configure(config.apiVersion, config.activationKey);
29
+ }
30
+ static configure(apiVersion, activationKey) {
31
+ MendAuthSevice.configured = false;
32
+ MendAuthSevice.configurationError = "";
33
+ MendAuthSevice.baseUrl = "";
34
+ MendAuthSevice.clientEmail = "";
35
+ MendAuthSevice.clientKey = "";
36
+ MendAuthSevice.clientUrl = "";
37
+ if (!activationKey) {
38
+ MendAuthSevice.configurationError = "Mend activation key is not configured. Please set the Activation Key in the configuration file.";
39
+ MendAuthSevice.logger?.warn(MendAuthSevice.configurationError);
40
+ return;
41
+ }
24
42
  try {
25
43
  const licenseKey = auth_service_helpers.caesarCipherDecrypt(activationKey);
26
44
  const decoded = jwt__default.default.decode(licenseKey);
27
45
  if (!decoded || typeof decoded !== "object") {
28
- throw new Error(
29
- "Invalid activation key: could not decode license payload"
30
- );
46
+ MendAuthSevice.configurationError = "Invalid activation key. Please provide the valid Activation Key.";
47
+ MendAuthSevice.logger.error(MendAuthSevice.configurationError);
48
+ return;
31
49
  }
32
50
  const jwtPayload = decoded;
33
51
  const { wsEnvUrl, integratorEmail, userKey } = jwtPayload || {};
34
52
  if (!wsEnvUrl || typeof wsEnvUrl !== "string" || !integratorEmail || typeof integratorEmail !== "string" || !userKey || typeof userKey !== "string") {
35
- throw new Error(
36
- "Invalid activation key: missing required fields (wsEnvUrl, integratorEmail, userKey)"
53
+ MendAuthSevice.configurationError = "Invalid activation key. Please provide the valid Activation Key.";
54
+ MendAuthSevice.logger.error(
55
+ "Invalid activation key: missing required fields (wsEnvUrl, integratorEmail, userKey)."
37
56
  );
57
+ return;
38
58
  }
39
59
  let baseUrl;
40
60
  try {
41
61
  baseUrl = new URL(wsEnvUrl);
42
62
  } catch {
43
- throw new Error("Invalid activation key: wsEnvUrl is not a valid URL");
63
+ MendAuthSevice.configurationError = "Invalid activation key. Please provide the valid Activation Key.";
64
+ MendAuthSevice.logger.error(
65
+ "Invalid activation key: wsEnvUrl is not a valid URL."
66
+ );
67
+ return;
44
68
  }
45
69
  baseUrl.hostname = `api-${baseUrl.hostname}`;
46
70
  baseUrl.pathname = `/api/${apiVersion}`;
@@ -48,12 +72,17 @@ class MendAuthSevice {
48
72
  MendAuthSevice.clientEmail = integratorEmail;
49
73
  MendAuthSevice.clientKey = userKey;
50
74
  MendAuthSevice.clientUrl = wsEnvUrl;
75
+ MendAuthSevice.configured = true;
51
76
  } catch (err) {
77
+ MendAuthSevice.configurationError = "Something went wrong while configuring Mend. Please check the Activation Key.";
78
+ MendAuthSevice.logger?.error(
79
+ `Unexpected error while configuring Mend: ${err instanceof Error ? err.message : String(err)}`
80
+ );
52
81
  MendAuthSevice.baseUrl = "";
53
82
  MendAuthSevice.clientEmail = "";
54
83
  MendAuthSevice.clientKey = "";
55
84
  MendAuthSevice.clientUrl = "";
56
- throw err instanceof Error ? err : new Error(String(err));
85
+ MendAuthSevice.configured = false;
57
86
  }
58
87
  }
59
88
  static async login() {
@@ -134,6 +163,12 @@ class MendAuthSevice {
134
163
  static getClientName() {
135
164
  return MendAuthSevice.clientName;
136
165
  }
166
+ static isConfigured() {
167
+ return MendAuthSevice.configured;
168
+ }
169
+ static getConfigurationError() {
170
+ return MendAuthSevice.configurationError;
171
+ }
137
172
  }
138
173
 
139
174
  exports.MendAuthSevice = MendAuthSevice;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.service.cjs.js","sources":["../../src/service/auth.service.ts"],"sourcesContent":["import jwt from 'jsonwebtoken';\nimport { post } from '../api';\nimport { caesarCipherDecrypt } from './auth.service.helpers';\nimport {\n JwtAuthToken,\n JwtLicenceKeyPayload,\n LoginSuccessResponseData,\n MendConfig,\n RefreshAccessTokenSuccessResponseData,\n} from './auth.services.types';\n\nenum AuthRoutes {\n LOGIN = '/login',\n REFRESH_TOKEN = '/login/accessToken',\n}\n\nexport class MendAuthSevice {\n private static authToken = '';\n private static refreshToken = '';\n private static baseUrl = '';\n private static clientEmail = '';\n private static clientKey = '';\n private static clientUrl = '';\n private static clientName = '';\n private static clientUuid = '';\n\n constructor(config: MendConfig) {\n this.getConfig(config.apiVersion, config.activationKey);\n }\n\n private getConfig(apiVersion: string, activationKey: string) {\n try {\n const licenseKey = caesarCipherDecrypt(activationKey);\n\n // Decode the license key and validate payload shape\n const decoded = jwt.decode(licenseKey);\n if (!decoded || typeof decoded !== 'object') {\n throw new Error(\n 'Invalid activation key: could not decode license payload',\n );\n }\n const jwtPayload = decoded as JwtLicenceKeyPayload;\n\n const { wsEnvUrl, integratorEmail, userKey } =\n (jwtPayload as Partial<JwtLicenceKeyPayload>) || {};\n\n // Validate required fields presence and types\n if (\n !wsEnvUrl ||\n typeof wsEnvUrl !== 'string' ||\n !integratorEmail ||\n typeof integratorEmail !== 'string' ||\n !userKey ||\n typeof userKey !== 'string'\n ) {\n throw new Error(\n 'Invalid activation key: missing required fields (wsEnvUrl, integratorEmail, userKey)',\n );\n }\n\n // Create a baseUrl from the environment url with safety checks\n let baseUrl: URL;\n try {\n baseUrl = new URL(wsEnvUrl);\n } catch {\n throw new Error('Invalid activation key: wsEnvUrl is not a valid URL');\n }\n baseUrl.hostname = `api-${baseUrl.hostname}`;\n baseUrl.pathname = `/api/${apiVersion}`;\n\n MendAuthSevice.baseUrl = baseUrl.toString();\n MendAuthSevice.clientEmail = integratorEmail;\n MendAuthSevice.clientKey = userKey;\n MendAuthSevice.clientUrl = wsEnvUrl;\n } catch (err) {\n // Log and reset to safe defaults, then rethrow so callers can decide how to handle it\n MendAuthSevice.baseUrl = '';\n MendAuthSevice.clientEmail = '';\n MendAuthSevice.clientKey = '';\n MendAuthSevice.clientUrl = '';\n throw err instanceof Error ? err : new Error(String(err));\n }\n }\n\n private static async login(): Promise<void> {\n return post<LoginSuccessResponseData>(AuthRoutes.LOGIN, {\n body: {\n email: this.clientEmail,\n userKey: this.clientKey,\n },\n })\n .then(data => {\n if (!data?.response?.refreshToken) {\n throw new Error('Login failed: missing refreshToken in response');\n }\n this.refreshToken = data.response.refreshToken;\n return Promise.resolve();\n })\n .catch(err => {\n this.refreshToken = '';\n return Promise.reject(err);\n });\n }\n\n private static async refreshAccessToken(): Promise<void> {\n return post<RefreshAccessTokenSuccessResponseData>(\n AuthRoutes.REFRESH_TOKEN,\n {\n headers: {\n 'wss-refresh-token': this.refreshToken,\n },\n },\n )\n .then(data => {\n if (!data?.response?.jwtToken) {\n throw new Error('Refresh token failed: missing jwtToken in response');\n }\n this.authToken = data.response.jwtToken;\n this.clientName = data.response.orgName ?? '';\n this.clientUuid = data.response.orgUuid ?? '';\n return Promise.resolve();\n })\n .catch(err => {\n this.authToken = '';\n this.clientName = '';\n this.clientUuid = '';\n return Promise.reject(err);\n });\n }\n\n static async connect(): Promise<void> {\n return MendAuthSevice.login()\n .then(() => MendAuthSevice.refreshAccessToken())\n .catch(err => {\n return Promise.reject(err);\n });\n }\n\n static async validateAuthToken(url: string): Promise<void> {\n if (\n [AuthRoutes.LOGIN, AuthRoutes.REFRESH_TOKEN].includes(url as AuthRoutes)\n ) {\n return Promise.resolve();\n }\n\n if (!this.authToken) {\n return this.connect();\n }\n\n const decoded = jwt.decode(this.authToken);\n if (!decoded || typeof decoded !== 'object' || !('exp' in decoded)) {\n return this.connect();\n }\n\n const token = decoded as JwtAuthToken;\n const expMs = Number(token.exp) * 1000;\n if (Number.isNaN(expMs) || expMs - Date.now() < 0) {\n return this.connect();\n }\n\n return Promise.resolve();\n }\n\n static getAuthToken(): string {\n return MendAuthSevice.authToken;\n }\n\n static getBaseUrl(): string {\n return MendAuthSevice.baseUrl;\n }\n\n static getOrganizationUuid(): string {\n return MendAuthSevice.clientUuid;\n }\n\n static getClientUrl(): string {\n return MendAuthSevice.clientUrl;\n }\n\n static getClientName(): string {\n return MendAuthSevice.clientName;\n }\n}\n"],"names":["caesarCipherDecrypt","jwt","post"],"mappings":"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"}
1
+ {"version":3,"file":"auth.service.cjs.js","sources":["../../src/service/auth.service.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport jwt from 'jsonwebtoken';\nimport { post } from '../api';\nimport { caesarCipherDecrypt } from './auth.service.helpers';\nimport {\n JwtAuthToken,\n JwtLicenceKeyPayload,\n LoginSuccessResponseData,\n MendConfig,\n RefreshAccessTokenSuccessResponseData,\n} from './auth.services.types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nenum AuthRoutes {\n LOGIN = '/login',\n REFRESH_TOKEN = '/login/accessToken',\n}\n\nexport class MendAuthSevice {\n private static authToken = '';\n private static refreshToken = '';\n private static baseUrl = '';\n private static clientEmail = '';\n private static clientKey = '';\n private static clientUrl = '';\n private static clientName = '';\n private static clientUuid = '';\n private static configured = false;\n private static configurationError = '';\n private static logger: LoggerService;\n\n constructor(config: MendConfig) {\n MendAuthSevice.init(config);\n }\n\n static init(config: MendConfig) {\n MendAuthSevice.logger = config.logger;\n MendAuthSevice.configure(config.apiVersion, config.activationKey);\n }\n\n private static configure(apiVersion: string, activationKey: string) {\n // Reset configuration state\n MendAuthSevice.configured = false;\n MendAuthSevice.configurationError = '';\n MendAuthSevice.baseUrl = '';\n MendAuthSevice.clientEmail = '';\n MendAuthSevice.clientKey = '';\n MendAuthSevice.clientUrl = '';\n\n // If no activation key provided, leave unconfigured but don't throw\n if (!activationKey) {\n MendAuthSevice.configurationError =\n 'Mend activation key is not configured. Please set the Activation Key in the configuration file.';\n MendAuthSevice.logger?.warn(MendAuthSevice.configurationError);\n return;\n }\n\n try {\n const licenseKey = caesarCipherDecrypt(activationKey);\n\n // Decode the license key and validate payload shape\n const decoded = jwt.decode(licenseKey);\n if (!decoded || typeof decoded !== 'object') {\n MendAuthSevice.configurationError =\n 'Invalid activation key. Please provide the valid Activation Key.';\n MendAuthSevice.logger.error(MendAuthSevice.configurationError);\n return;\n }\n const jwtPayload = decoded as JwtLicenceKeyPayload;\n\n const { wsEnvUrl, integratorEmail, userKey } =\n (jwtPayload as Partial<JwtLicenceKeyPayload>) || {};\n\n // Validate required fields presence and types\n if (\n !wsEnvUrl ||\n typeof wsEnvUrl !== 'string' ||\n !integratorEmail ||\n typeof integratorEmail !== 'string' ||\n !userKey ||\n typeof userKey !== 'string'\n ) {\n MendAuthSevice.configurationError =\n 'Invalid activation key. Please provide the valid Activation Key.';\n MendAuthSevice.logger.error(\n 'Invalid activation key: missing required fields (wsEnvUrl, integratorEmail, userKey).',\n );\n return;\n }\n\n // Create a baseUrl from the environment url with safety checks\n let baseUrl: URL;\n try {\n baseUrl = new URL(wsEnvUrl);\n } catch {\n MendAuthSevice.configurationError =\n 'Invalid activation key. Please provide the valid Activation Key.';\n MendAuthSevice.logger.error(\n 'Invalid activation key: wsEnvUrl is not a valid URL.',\n );\n return;\n }\n baseUrl.hostname = `api-${baseUrl.hostname}`;\n baseUrl.pathname = `/api/${apiVersion}`;\n\n MendAuthSevice.baseUrl = baseUrl.toString();\n MendAuthSevice.clientEmail = integratorEmail;\n MendAuthSevice.clientKey = userKey;\n MendAuthSevice.clientUrl = wsEnvUrl;\n MendAuthSevice.configured = true;\n } catch (err) {\n MendAuthSevice.configurationError =\n 'Something went wrong while configuring Mend. Please check the Activation Key.';\n MendAuthSevice.logger?.error(\n `Unexpected error while configuring Mend: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n MendAuthSevice.baseUrl = '';\n MendAuthSevice.clientEmail = '';\n MendAuthSevice.clientKey = '';\n MendAuthSevice.clientUrl = '';\n MendAuthSevice.configured = false;\n }\n }\n\n private static async login(): Promise<void> {\n return post<LoginSuccessResponseData>(AuthRoutes.LOGIN, {\n body: {\n email: this.clientEmail,\n userKey: this.clientKey,\n },\n })\n .then(data => {\n if (!data?.response?.refreshToken) {\n throw new Error('Login failed: missing refreshToken in response');\n }\n this.refreshToken = data.response.refreshToken;\n return Promise.resolve();\n })\n .catch(err => {\n this.refreshToken = '';\n return Promise.reject(err);\n });\n }\n\n private static async refreshAccessToken(): Promise<void> {\n return post<RefreshAccessTokenSuccessResponseData>(\n AuthRoutes.REFRESH_TOKEN,\n {\n headers: {\n 'wss-refresh-token': this.refreshToken,\n },\n },\n )\n .then(data => {\n if (!data?.response?.jwtToken) {\n throw new Error('Refresh token failed: missing jwtToken in response');\n }\n this.authToken = data.response.jwtToken;\n this.clientName = data.response.orgName ?? '';\n this.clientUuid = data.response.orgUuid ?? '';\n return Promise.resolve();\n })\n .catch(err => {\n this.authToken = '';\n this.clientName = '';\n this.clientUuid = '';\n return Promise.reject(err);\n });\n }\n\n static async connect(): Promise<void> {\n return MendAuthSevice.login()\n .then(() => MendAuthSevice.refreshAccessToken())\n .catch(err => {\n return Promise.reject(err);\n });\n }\n\n static async validateAuthToken(url: string): Promise<void> {\n if (\n [AuthRoutes.LOGIN, AuthRoutes.REFRESH_TOKEN].includes(url as AuthRoutes)\n ) {\n return Promise.resolve();\n }\n\n if (!this.authToken) {\n return this.connect();\n }\n\n const decoded = jwt.decode(this.authToken);\n if (!decoded || typeof decoded !== 'object' || !('exp' in decoded)) {\n return this.connect();\n }\n\n const token = decoded as JwtAuthToken;\n const expMs = Number(token.exp) * 1000;\n if (Number.isNaN(expMs) || expMs - Date.now() < 0) {\n return this.connect();\n }\n\n return Promise.resolve();\n }\n\n static getAuthToken(): string {\n return MendAuthSevice.authToken;\n }\n\n static getBaseUrl(): string {\n return MendAuthSevice.baseUrl;\n }\n\n static getOrganizationUuid(): string {\n return MendAuthSevice.clientUuid;\n }\n\n static getClientUrl(): string {\n return MendAuthSevice.clientUrl;\n }\n\n static getClientName(): string {\n return MendAuthSevice.clientName;\n }\n\n static isConfigured(): boolean {\n return MendAuthSevice.configured;\n }\n\n static getConfigurationError(): string {\n return MendAuthSevice.configurationError;\n }\n}\n"],"names":["caesarCipherDecrypt","jwt","post"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.service.helpers.cjs.js","sources":["../../src/service/auth.service.helpers.ts"],"sourcesContent":["export const caesarCipherDecrypt = (activationKey: string): string => {\n let tmp = '';\n const OFFSET = 4;\n for (let i = 0; i < activationKey.length; i++) {\n tmp += String.fromCharCode(activationKey.charCodeAt(i) - OFFSET);\n }\n\n const reversed = tmp.split('').reverse().join('');\n return Buffer.from(reversed, 'base64').toString();\n};\n"],"names":[],"mappings":";;AAAa,MAAA,mBAAA,GAAsB,CAAC,aAAkC,KAAA;AACpE,EAAA,IAAI,GAAM,GAAA,EAAA;AACV,EAAA,MAAM,MAAS,GAAA,CAAA;AACf,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,aAAA,CAAc,QAAQ,CAAK,EAAA,EAAA;AAC7C,IAAA,GAAA,IAAO,OAAO,YAAa,CAAA,aAAA,CAAc,UAAW,CAAA,CAAC,IAAI,MAAM,CAAA;AAAA;AAGjE,EAAM,MAAA,QAAA,GAAW,IAAI,KAAM,CAAA,EAAE,EAAE,OAAQ,EAAA,CAAE,KAAK,EAAE,CAAA;AAChD,EAAA,OAAO,MAAO,CAAA,IAAA,CAAK,QAAU,EAAA,QAAQ,EAAE,QAAS,EAAA;AAClD;;;;"}
1
+ {"version":3,"file":"auth.service.helpers.cjs.js","sources":["../../src/service/auth.service.helpers.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport const caesarCipherDecrypt = (activationKey: string): string => {\n let tmp = '';\n const OFFSET = 4;\n for (let i = 0; i < activationKey.length; i++) {\n tmp += String.fromCharCode(activationKey.charCodeAt(i) - OFFSET);\n }\n\n const reversed = tmp.split('').reverse().join('');\n return Buffer.from(reversed, 'base64').toString();\n};\n"],"names":[],"mappings":";;AAeO,MAAM,mBAAA,GAAsB,CAAC,aAAA,KAAkC;AACpE,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,MAAM,MAAA,GAAS,CAAA;AACf,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,aAAA,CAAc,QAAQ,CAAA,EAAA,EAAK;AAC7C,IAAA,GAAA,IAAO,OAAO,YAAA,CAAa,aAAA,CAAc,UAAA,CAAW,CAAC,IAAI,MAAM,CAAA;AAAA,EACjE;AAEA,EAAA,MAAM,QAAA,GAAW,IAAI,KAAA,CAAM,EAAE,EAAE,OAAA,EAAQ,CAAE,KAAK,EAAE,CAAA;AAChD,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,QAAA,EAAU,QAAQ,EAAE,QAAA,EAAS;AAClD;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"data.service.cjs.js","sources":["../../src/service/data.service.ts"],"sourcesContent":["import { get, post } from '../api';\nimport { MendAuthSevice } from './auth.service';\nimport {\n GetOrganizationProjectRequestData,\n GetProjectStatisticsRequestData,\n GetCodeFindingsRequestData,\n GetDependenciesFindingsRequestData,\n GetContainersFindingsRequestData,\n GetOrganizationProjectSuccessResponseData,\n GetProjectStatisticsSuccessResponseData,\n GetCodeFindingSuccessResponseData,\n GetDependenciesFindingSuccessResponseData,\n GetContainersFindingSuccessResponseData,\n} from './data.service.types';\n\nexport class MendDataService extends MendAuthSevice {\n async getOrganizationProject({\n queryParams,\n }: GetOrganizationProjectRequestData): Promise<GetOrganizationProjectSuccessResponseData> {\n return get(`/orgs/${MendAuthSevice.getOrganizationUuid()}/projects`, {\n params: {\n ...queryParams,\n },\n });\n }\n\n async getProjectStatistics({\n queryParams,\n bodyParams,\n }: GetProjectStatisticsRequestData): Promise<GetProjectStatisticsSuccessResponseData> {\n return post(\n `/orgs/${MendAuthSevice.getOrganizationUuid()}/projects/summaries`,\n {\n params: {\n ...queryParams,\n },\n body: {\n ...bodyParams,\n },\n },\n );\n }\n\n async getCodeFinding({\n pathParams,\n queryParams,\n }: GetCodeFindingsRequestData): Promise<GetCodeFindingSuccessResponseData> {\n return get(`/projects/${pathParams.uuid}/code/findings`, {\n params: {\n ...queryParams,\n },\n });\n }\n\n async getDependenciesFinding({\n pathParams,\n queryParams,\n }: GetDependenciesFindingsRequestData): Promise<GetDependenciesFindingSuccessResponseData> {\n return get(`/projects/${pathParams.uuid}/dependencies/findings/security`, {\n params: {\n ...queryParams,\n },\n });\n }\n\n async getContainersFinding({\n pathParams,\n queryParams,\n }: GetContainersFindingsRequestData): Promise<GetContainersFindingSuccessResponseData> {\n return get(`/projects/${pathParams.uuid}/images/findings/security`, {\n params: {\n ...queryParams,\n },\n });\n }\n}\n"],"names":["MendAuthSevice","get","post"],"mappings":";;;;;AAeO,MAAM,wBAAwBA,2BAAe,CAAA;AAAA,EAClD,MAAM,sBAAuB,CAAA;AAAA,IAC3B;AAAA,GACwF,EAAA;AACxF,IAAA,OAAOC,SAAI,CAAA,CAAA,MAAA,EAASD,2BAAe,CAAA,mBAAA,EAAqB,CAAa,SAAA,CAAA,EAAA;AAAA,MACnE,MAAQ,EAAA;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA;AACH,EAEA,MAAM,oBAAqB,CAAA;AAAA,IACzB,WAAA;AAAA,IACA;AAAA,GACoF,EAAA;AACpF,IAAO,OAAAE,UAAA;AAAA,MACL,CAAA,MAAA,EAASF,2BAAe,CAAA,mBAAA,EAAqB,CAAA,mBAAA,CAAA;AAAA,MAC7C;AAAA,QACE,MAAQ,EAAA;AAAA,UACN,GAAG;AAAA,SACL;AAAA,QACA,IAAM,EAAA;AAAA,UACJ,GAAG;AAAA;AACL;AACF,KACF;AAAA;AACF,EAEA,MAAM,cAAe,CAAA;AAAA,IACnB,UAAA;AAAA,IACA;AAAA,GACyE,EAAA;AACzE,IAAA,OAAOC,SAAI,CAAA,CAAA,UAAA,EAAa,UAAW,CAAA,IAAI,CAAkB,cAAA,CAAA,EAAA;AAAA,MACvD,MAAQ,EAAA;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA;AACH,EAEA,MAAM,sBAAuB,CAAA;AAAA,IAC3B,UAAA;AAAA,IACA;AAAA,GACyF,EAAA;AACzF,IAAA,OAAOA,SAAI,CAAA,CAAA,UAAA,EAAa,UAAW,CAAA,IAAI,CAAmC,+BAAA,CAAA,EAAA;AAAA,MACxE,MAAQ,EAAA;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA;AACH,EAEA,MAAM,oBAAqB,CAAA;AAAA,IACzB,UAAA;AAAA,IACA;AAAA,GACqF,EAAA;AACrF,IAAA,OAAOA,SAAI,CAAA,CAAA,UAAA,EAAa,UAAW,CAAA,IAAI,CAA6B,yBAAA,CAAA,EAAA;AAAA,MAClE,MAAQ,EAAA;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA;AAEL;;;;"}
1
+ {"version":3,"file":"data.service.cjs.js","sources":["../../src/service/data.service.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { get, post } from '../api';\nimport { MendAuthSevice } from './auth.service';\nimport {\n GetOrganizationProjectRequestData,\n GetProjectStatisticsRequestData,\n GetCodeFindingsRequestData,\n GetDependenciesFindingsRequestData,\n GetContainersFindingsRequestData,\n GetOrganizationProjectSuccessResponseData,\n GetProjectStatisticsSuccessResponseData,\n GetCodeFindingSuccessResponseData,\n GetDependenciesFindingSuccessResponseData,\n GetContainersFindingSuccessResponseData,\n} from './data.service.types';\n\nexport class MendDataService extends MendAuthSevice {\n async getOrganizationProject({\n queryParams,\n }: GetOrganizationProjectRequestData): Promise<GetOrganizationProjectSuccessResponseData> {\n return get(`/orgs/${MendAuthSevice.getOrganizationUuid()}/projects`, {\n params: {\n ...queryParams,\n },\n });\n }\n\n async getProjectStatistics({\n queryParams,\n bodyParams,\n }: GetProjectStatisticsRequestData): Promise<GetProjectStatisticsSuccessResponseData> {\n return post(\n `/orgs/${MendAuthSevice.getOrganizationUuid()}/projects/summaries`,\n {\n params: {\n ...queryParams,\n },\n body: {\n ...bodyParams,\n },\n },\n );\n }\n\n async getCodeFinding({\n pathParams,\n queryParams,\n }: GetCodeFindingsRequestData): Promise<GetCodeFindingSuccessResponseData> {\n return get(`/projects/${pathParams.uuid}/code/findings`, {\n params: {\n ...queryParams,\n },\n });\n }\n\n async getDependenciesFinding({\n pathParams,\n queryParams,\n }: GetDependenciesFindingsRequestData): Promise<GetDependenciesFindingSuccessResponseData> {\n return get(`/projects/${pathParams.uuid}/dependencies/findings/security`, {\n params: {\n ...queryParams,\n },\n });\n }\n\n async getContainersFinding({\n pathParams,\n queryParams,\n }: GetContainersFindingsRequestData): Promise<GetContainersFindingSuccessResponseData> {\n return get(`/projects/${pathParams.uuid}/images/findings/security`, {\n params: {\n ...queryParams,\n },\n });\n }\n}\n"],"names":["MendAuthSevice","get","post"],"mappings":";;;;;AA8BO,MAAM,wBAAwBA,2BAAA,CAAe;AAAA,EAClD,MAAM,sBAAA,CAAuB;AAAA,IAC3B;AAAA,GACF,EAA0F;AACxF,IAAA,OAAOC,SAAA,CAAI,CAAA,MAAA,EAASD,2BAAA,CAAe,mBAAA,EAAqB,CAAA,SAAA,CAAA,EAAa;AAAA,MACnE,MAAA,EAAQ;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,oBAAA,CAAqB;AAAA,IACzB,WAAA;AAAA,IACA;AAAA,GACF,EAAsF;AACpF,IAAA,OAAOE,UAAA;AAAA,MACL,CAAA,MAAA,EAASF,2BAAA,CAAe,mBAAA,EAAqB,CAAA,mBAAA,CAAA;AAAA,MAC7C;AAAA,QACE,MAAA,EAAQ;AAAA,UACN,GAAG;AAAA,SACL;AAAA,QACA,IAAA,EAAM;AAAA,UACJ,GAAG;AAAA;AACL;AACF,KACF;AAAA,EACF;AAAA,EAEA,MAAM,cAAA,CAAe;AAAA,IACnB,UAAA;AAAA,IACA;AAAA,GACF,EAA2E;AACzE,IAAA,OAAOC,SAAA,CAAI,CAAA,UAAA,EAAa,UAAA,CAAW,IAAI,CAAA,cAAA,CAAA,EAAkB;AAAA,MACvD,MAAA,EAAQ;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,sBAAA,CAAuB;AAAA,IAC3B,UAAA;AAAA,IACA;AAAA,GACF,EAA2F;AACzF,IAAA,OAAOA,SAAA,CAAI,CAAA,UAAA,EAAa,UAAA,CAAW,IAAI,CAAA,+BAAA,CAAA,EAAmC;AAAA,MACxE,MAAA,EAAQ;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,oBAAA,CAAqB;AAAA,IACzB,UAAA;AAAA,IACA;AAAA,GACF,EAAuF;AACrF,IAAA,OAAOA,SAAA,CAAI,CAAA,UAAA,EAAa,UAAA,CAAW,IAAI,CAAA,yBAAA,CAAA,EAA6B;AAAA,MAClE,MAAA,EAAQ;AAAA,QACN,GAAG;AAAA;AACL,KACD,CAAA;AAAA,EACH;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"data.service.helpers.cjs.js","sources":["../../src/service/data.service.helpers.ts"],"sourcesContent":["import { Entity } from '@backstage/catalog-model';\nimport { match } from 'path-to-regexp';\nimport type { QueryParams } from '../api';\nimport {\n ProjectStatisticsSuccessResponseData,\n EntityURL,\n OrganizationProjectSuccessResponseData,\n PaginationQueryParams,\n Project,\n CodeFindingSuccessResponseData,\n DependenciesFindingSuccessResponseData,\n ContainersFindingSuccessResponseData,\n Finding,\n StatisticsEngine,\n StatisticsName,\n} from './data.service.types';\nimport { AZURE_HOST_NAME } from '../constants';\n\nenum FINDING_TYPE {\n DEPENDENCIES = 'ALERTS',\n CODE = 'SAST_VULNERABILITIES_BY_SEVERITY',\n CONTAINERS = 'IMG_SECURITY',\n LAST_SCAN = 'LAST_SCAN',\n}\n\ntype OverviewData = {\n projectList: Project[];\n};\n\nexport const dataProjectParser = (\n projectStatistics: Array<\n ProjectStatisticsSuccessResponseData & { entity: EntityURL }\n >,\n organizationProjects: OrganizationProjectSuccessResponseData[],\n) => {\n const organizationData = organizationProjects.reduce((prev, next) => {\n prev[next.uuid] = next;\n return prev;\n }, {} as { [key: string]: OrganizationProjectSuccessResponseData });\n\n const projectData = projectStatistics.reduce(\n (\n prev: OverviewData,\n next: ProjectStatisticsSuccessResponseData & { entity: EntityURL },\n ) => {\n const dependenciesCritical =\n next.statistics[FINDING_TYPE.DEPENDENCIES]\n .criticalSeverityVulnerabilities;\n const dependenciesHigh =\n next.statistics[FINDING_TYPE.DEPENDENCIES].highSeverityVulnerabilities;\n const dependenciesMedium =\n next.statistics[FINDING_TYPE.DEPENDENCIES]\n .mediumSeverityVulnerabilities;\n const dependenciesLow =\n next.statistics[FINDING_TYPE.DEPENDENCIES].lowSeverityVulnerabilities;\n const dependeciesTotal =\n dependenciesCritical +\n dependenciesHigh +\n dependenciesMedium +\n dependenciesLow;\n\n const codeHigh =\n next.statistics[FINDING_TYPE.CODE].sastHighVulnerabilities;\n const codeMedium =\n next.statistics[FINDING_TYPE.CODE].sastMediumVulnerabilities;\n const codeLow = next.statistics[FINDING_TYPE.CODE].sastLowVulnerabilities;\n const codeTotal = codeHigh + codeMedium + codeLow;\n\n const containersCritical =\n next.statistics[FINDING_TYPE.CONTAINERS].imgCriticalVulnerabilities;\n const containersHigh =\n next.statistics[FINDING_TYPE.CONTAINERS].imgHighVulnerabilities;\n const containersMedium =\n next.statistics[FINDING_TYPE.CONTAINERS].imgMediumVulnerabilities;\n const containersLow =\n next.statistics[FINDING_TYPE.CONTAINERS].imgLowVulnerabilities;\n const containersTotal =\n containersCritical + containersHigh + containersMedium + containersLow;\n\n const criticalTotal = dependenciesCritical + containersCritical;\n const highTotal = dependenciesHigh + codeHigh + containersHigh;\n const mediumTotal = dependenciesMedium + codeMedium + containersMedium;\n const lowTotal = dependenciesLow + codeLow + containersLow;\n const total = dependeciesTotal + codeTotal + containersTotal;\n\n const statistics = {\n [StatisticsEngine.DEPENDENCIES]: {\n critical: dependenciesCritical,\n high: dependenciesHigh,\n medium: dependenciesMedium,\n low: dependenciesLow,\n total: dependeciesTotal,\n },\n [StatisticsEngine.CODE]: {\n critical: null,\n high: codeHigh,\n medium: codeMedium,\n low: codeLow,\n total: codeTotal,\n },\n [StatisticsEngine.CONTAINERS]: {\n critical: containersCritical,\n high: containersHigh,\n medium: containersMedium,\n low: containersLow,\n total: containersTotal,\n },\n critical: criticalTotal,\n high: highTotal,\n medium: mediumTotal,\n low: lowTotal,\n total: total,\n };\n\n const project = {\n statistics,\n uuid: next.uuid,\n name: next.name,\n path: next.path,\n entity: next.entity,\n applicationName: organizationData[next.uuid].applicationName,\n applicationUuid: next.applicationUuid,\n lastScan: next.statistics[FINDING_TYPE.LAST_SCAN].lastScanTime,\n languages: next.statistics?.LIBRARY_TYPE_HISTOGRAM\n ? Object.entries(next.statistics.LIBRARY_TYPE_HISTOGRAM).sort(\n (a, b) => b[1] - a[1],\n )\n : ([] as [string, number][]),\n };\n\n prev.projectList.unshift(project);\n return prev;\n },\n {\n projectList: [],\n },\n );\n\n projectData.projectList.sort(\n (a, b) => b.statistics.critical - a.statistics.critical,\n );\n\n return projectData;\n};\n\nexport const parseEntityURL = (entityUrl?: string) => {\n try {\n if (!entityUrl) {\n return null;\n }\n\n const matches = entityUrl.match(\n /https?:\\/\\/[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,}(:[0-9]{1,5})?(\\/.*)?/g,\n );\n\n if (!matches) {\n return null;\n }\n const url = new URL(matches[0]);\n const hostname = url.host.toLowerCase();\n let matcher = match('/:org/:repo', { end: false });\n\n if (hostname === AZURE_HOST_NAME) {\n matcher = match('/:org/:project/_git/:repo', { end: false });\n }\n const extractedContent = matcher(url.pathname);\n if (extractedContent) {\n return { ...extractedContent, host: hostname };\n }\n return null;\n } catch (error) {\n return null;\n }\n};\n\nexport const dataMatcher = (\n entities: Entity[],\n projects: ProjectStatisticsSuccessResponseData[],\n) => {\n const projectSourceURL = getSourceURLWiseProject(projects);\n return entities.reduce(\n (\n prev: Array<\n ProjectStatisticsSuccessResponseData & {\n entity: EntityURL;\n }\n >,\n next: Entity,\n ) => {\n const entityURL = parseEntityURL(\n next?.metadata?.annotations?.['backstage.io/source-location'],\n );\n\n if (!entityURL) {\n return prev;\n }\n\n // NOTE: Find project based on Github URL\n const relatedProjects =\n projectSourceURL[`${entityURL?.host}${entityURL?.path}`]?.projectObjs;\n\n if (!relatedProjects) {\n return prev;\n }\n\n const entity = {\n path: entityURL.path,\n params: entityURL.params,\n namespace: next.metadata.namespace,\n kind: 'component',\n source: 'catalog',\n };\n\n relatedProjects.forEach(project => prev.push({ ...project, entity }));\n\n return prev;\n },\n [],\n );\n};\n\n/**\n * Extracts the source URL details from each project and returns a dictionary\n * where each key is a combination of the URL's host and pathname,\n * and the value is an object containing the original project and the parsed source URL data.\n *\n * @param projects Array of ProjectStatisticsSuccessResponseData\n * @returns A dictionary object with keys as `${host}${pathname}` strings extracted from sourceUrl and values as:\n * {\n * projectObjs: ProjectStatisticsSuccessResponseData[];\n sourceUrl: string | null;\n host: string | null;\n pathname: string | null;\n * }\n */\nexport function getSourceURLWiseProject(\n projects: ProjectStatisticsSuccessResponseData[],\n) {\n return projects.reduce(\n (acc, project) => {\n const projectTags = project.tags as Array<{ key: string; value: string }>;\n const sourceUrlTag = projectTags?.find(tag => tag.key === 'sourceUrl');\n let host = null;\n let pathname = null;\n let sourceUrl = null;\n\n if (sourceUrlTag && typeof sourceUrlTag.value === 'string') {\n sourceUrl = sourceUrlTag.value;\n const urlString = sourceUrl.startsWith('http')\n ? sourceUrl\n : `https://${sourceUrl}`;\n\n try {\n const urlObj = new URL(urlString);\n host = urlObj.host.toLocaleLowerCase();\n // Remove leading/trailing slashes and split\n pathname = urlObj.pathname;\n } catch (e) {\n // fallback: leave as nulls\n }\n }\n\n if (acc[`${host}${pathname}`]) {\n acc[`${host}${pathname}`].projectObjs.push(project);\n } else {\n acc[`${host}${pathname}`] = {\n projectObjs: [project],\n sourceUrl,\n host,\n pathname,\n };\n }\n return acc;\n },\n {} as Record<\n string,\n {\n projectObjs: ProjectStatisticsSuccessResponseData[];\n sourceUrl: string | null;\n host: string | null;\n pathname: string | null;\n }\n >,\n );\n}\n\nconst getIssueStatus = (\n engine: StatisticsEngine,\n finding:\n | CodeFindingSuccessResponseData\n | DependenciesFindingSuccessResponseData\n | ContainersFindingSuccessResponseData,\n): string => {\n if (engine === StatisticsEngine.CODE) {\n if ((finding as CodeFindingSuccessResponseData)?.suppressed)\n return 'suppressed';\n if (\n (finding as CodeFindingSuccessResponseData)?.almIssues?.jiraPlatform\n ?.issueStatus\n )\n return 'created';\n if ((finding as CodeFindingSuccessResponseData)?.reviewed)\n return 'reviewed';\n }\n\n if (engine === StatisticsEngine.DEPENDENCIES) {\n // NOTE: Available status: IGNORED and ACTIVE\n // ACTIVE means unreviewed\n // IGNORED means suppressed, comment fields are available to this status\n if (\n (finding as DependenciesFindingSuccessResponseData)?.findingInfo\n ?.status === 'IGNORED'\n )\n return 'suppressed';\n }\n\n return 'unreviewed';\n};\n\nexport const dataFindingParser = (\n code: CodeFindingSuccessResponseData[] = [],\n dependencies: DependenciesFindingSuccessResponseData[] = [],\n containers: ContainersFindingSuccessResponseData[] = [],\n projectName: string = '',\n) => {\n let codeFindings: Finding[] = [];\n let dependenciesFindings: Finding[] = [];\n let containersFindings: Finding[] = [];\n\n if (code.length) {\n codeFindings = code.map(finding => {\n return {\n kind: StatisticsEngine.CODE,\n level: finding.severity.toLowerCase() as StatisticsName,\n name: finding.type.cwe.title,\n origin: `${finding.sharedStep.file}:${finding.sharedStep.line}`,\n time: finding?.createdTime,\n projectId: finding.projectId,\n projectName: projectName,\n issue: {\n issueStatus: finding.almIssues.jiraPlatform.issueStatus,\n reporter: finding.almIssues.jiraPlatform.createdByName,\n creationDate: finding.almIssues.jiraPlatform.createdTime,\n ticketName: finding.almIssues.jiraPlatform.issueKey,\n link: `${finding.almIssues.jiraPlatform.publicLink}/browse/${finding.almIssues.jiraPlatform.issueKey}`,\n status: getIssueStatus(StatisticsEngine.CODE, finding),\n },\n };\n });\n }\n\n if (dependencies.length) {\n dependenciesFindings = dependencies.map(finding => {\n return {\n kind: StatisticsEngine.DEPENDENCIES,\n level: finding.vulnerability.severity.toLowerCase() as StatisticsName,\n name: finding.vulnerability.name,\n origin: finding.component.name,\n time: finding.vulnerability.modifiedDate,\n projectId: finding.project.uuid,\n projectName: projectName,\n issue: {\n issueStatus: '',\n reporter: '',\n creationDate: '',\n ticketName: '',\n link: '',\n status: getIssueStatus(StatisticsEngine.DEPENDENCIES, finding),\n },\n };\n });\n }\n\n if (containers.length) {\n containersFindings = containers.map(finding => {\n return {\n kind: StatisticsEngine.CONTAINERS,\n level: finding.severity.toLowerCase() as StatisticsName,\n name: finding.vulnerabilityId,\n origin: finding.packageName,\n time: finding.detectionDate,\n projectId: finding.projectUuid,\n projectName: projectName,\n issue: {\n issueStatus: '',\n reporter: '',\n creationDate: '',\n ticketName: '',\n link: '',\n status: getIssueStatus(StatisticsEngine.CONTAINERS, finding), // NOTE: Currently, issue for finding in containers no exist.\n },\n };\n });\n }\n\n const order: { [k: string]: number } = {\n critical: 1,\n high: 2,\n medium: 3,\n low: 4,\n };\n\n return [...codeFindings, ...dependenciesFindings, ...containersFindings].sort(\n (a, b) => {\n return order[a.level] - order[b.level];\n },\n );\n};\n\nconst parseQueryString = (href = '?'): QueryParams => {\n const [, queryString] = href.split('?');\n\n const queryParams: QueryParams = {};\n new URLSearchParams(queryString).forEach((val, key) => {\n queryParams[key] = val;\n });\n\n return queryParams;\n};\n\nexport const fetchQueryPagination = async <T>(cb: Function) => {\n const defaultQueryParams = { limit: '10000', cursor: '0' };\n const collection: T[] = [];\n\n const fetchLoop = async (queryParams: PaginationQueryParams) => {\n const result = await cb({ queryParams });\n\n collection.push(...result.response);\n\n const nextQuery = result.additionalData?.paging?.next;\n\n if (nextQuery) {\n const newQueryParams = parseQueryString(nextQuery);\n await fetchLoop(newQueryParams);\n }\n };\n\n await fetchLoop(defaultQueryParams);\n\n return collection;\n};\n"],"names":["StatisticsEngine","match","AZURE_HOST_NAME"],"mappings":"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"}
1
+ {"version":3,"file":"data.service.helpers.cjs.js","sources":["../../src/service/data.service.helpers.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity } from '@backstage/catalog-model';\nimport { match } from 'path-to-regexp';\nimport type { QueryParams } from '../api';\nimport {\n ProjectStatisticsSuccessResponseData,\n EntityURL,\n OrganizationProjectSuccessResponseData,\n PaginationQueryParams,\n Project,\n CodeFindingSuccessResponseData,\n DependenciesFindingSuccessResponseData,\n ContainersFindingSuccessResponseData,\n Finding,\n StatisticsEngine,\n StatisticsName,\n} from './data.service.types';\nimport { AZURE_HOST_NAME } from '../constants';\n\nenum FINDING_TYPE {\n DEPENDENCIES = 'ALERTS',\n CODE = 'SAST_VULNERABILITIES_BY_SEVERITY',\n CONTAINERS = 'IMG_SECURITY',\n LAST_SCAN = 'LAST_SCAN',\n}\n\ntype OverviewData = {\n projectList: Project[];\n};\n\nexport const dataProjectParser = (\n projectStatistics: Array<\n ProjectStatisticsSuccessResponseData & { entity: EntityURL }\n >,\n organizationProjects: OrganizationProjectSuccessResponseData[],\n) => {\n const organizationData = organizationProjects.reduce((prev, next) => {\n prev[next.uuid] = next;\n return prev;\n }, {} as { [key: string]: OrganizationProjectSuccessResponseData });\n\n const projectData = projectStatistics.reduce(\n (\n prev: OverviewData,\n next: ProjectStatisticsSuccessResponseData & { entity: EntityURL },\n ) => {\n const dependenciesCritical =\n next.statistics[FINDING_TYPE.DEPENDENCIES]\n .criticalSeverityVulnerabilities;\n const dependenciesHigh =\n next.statistics[FINDING_TYPE.DEPENDENCIES].highSeverityVulnerabilities;\n const dependenciesMedium =\n next.statistics[FINDING_TYPE.DEPENDENCIES]\n .mediumSeverityVulnerabilities;\n const dependenciesLow =\n next.statistics[FINDING_TYPE.DEPENDENCIES].lowSeverityVulnerabilities;\n const dependeciesTotal =\n dependenciesCritical +\n dependenciesHigh +\n dependenciesMedium +\n dependenciesLow;\n\n const codeHigh =\n next.statistics[FINDING_TYPE.CODE].sastHighVulnerabilities;\n const codeMedium =\n next.statistics[FINDING_TYPE.CODE].sastMediumVulnerabilities;\n const codeLow = next.statistics[FINDING_TYPE.CODE].sastLowVulnerabilities;\n const codeTotal = codeHigh + codeMedium + codeLow;\n\n const containersCritical =\n next.statistics[FINDING_TYPE.CONTAINERS].imgCriticalVulnerabilities;\n const containersHigh =\n next.statistics[FINDING_TYPE.CONTAINERS].imgHighVulnerabilities;\n const containersMedium =\n next.statistics[FINDING_TYPE.CONTAINERS].imgMediumVulnerabilities;\n const containersLow =\n next.statistics[FINDING_TYPE.CONTAINERS].imgLowVulnerabilities;\n const containersTotal =\n containersCritical + containersHigh + containersMedium + containersLow;\n\n const criticalTotal = dependenciesCritical + containersCritical;\n const highTotal = dependenciesHigh + codeHigh + containersHigh;\n const mediumTotal = dependenciesMedium + codeMedium + containersMedium;\n const lowTotal = dependenciesLow + codeLow + containersLow;\n const total = dependeciesTotal + codeTotal + containersTotal;\n\n const statistics = {\n [StatisticsEngine.DEPENDENCIES]: {\n critical: dependenciesCritical,\n high: dependenciesHigh,\n medium: dependenciesMedium,\n low: dependenciesLow,\n total: dependeciesTotal,\n },\n [StatisticsEngine.CODE]: {\n critical: null,\n high: codeHigh,\n medium: codeMedium,\n low: codeLow,\n total: codeTotal,\n },\n [StatisticsEngine.CONTAINERS]: {\n critical: containersCritical,\n high: containersHigh,\n medium: containersMedium,\n low: containersLow,\n total: containersTotal,\n },\n critical: criticalTotal,\n high: highTotal,\n medium: mediumTotal,\n low: lowTotal,\n total: total,\n };\n\n const project = {\n statistics,\n uuid: next.uuid,\n name: next.name,\n path: next.path,\n entity: next.entity,\n applicationName: organizationData[next.uuid].applicationName,\n applicationUuid: next.applicationUuid,\n lastScan: next.statistics[FINDING_TYPE.LAST_SCAN].lastScanTime,\n languages: next.statistics?.LIBRARY_TYPE_HISTOGRAM\n ? Object.entries(next.statistics.LIBRARY_TYPE_HISTOGRAM).sort(\n (a, b) => b[1] - a[1],\n )\n : ([] as [string, number][]),\n };\n\n prev.projectList.unshift(project);\n return prev;\n },\n {\n projectList: [],\n },\n );\n\n projectData.projectList.sort(\n (a, b) => b.statistics.critical - a.statistics.critical,\n );\n\n return projectData;\n};\n\nexport const parseEntityURL = (entityUrl?: string) => {\n try {\n if (!entityUrl) {\n return null;\n }\n\n const matches = entityUrl.match(\n /https?:\\/\\/[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,}(:[0-9]{1,5})?(\\/.*)?/g,\n );\n\n if (!matches) {\n return null;\n }\n const url = new URL(matches[0]);\n const hostname = url.host.toLowerCase();\n let matcher = match('/:org/:repo', { end: false });\n\n if (hostname === AZURE_HOST_NAME) {\n matcher = match('/:org/:project/_git/:repo', { end: false });\n }\n const extractedContent = matcher(url.pathname);\n if (extractedContent) {\n return { ...extractedContent, host: hostname };\n }\n return null;\n } catch (error) {\n return null;\n }\n};\n\nexport const dataMatcher = (\n entities: Entity[],\n projects: ProjectStatisticsSuccessResponseData[],\n) => {\n const projectSourceURL = getSourceURLWiseProject(projects);\n return entities.reduce(\n (\n prev: Array<\n ProjectStatisticsSuccessResponseData & {\n entity: EntityURL;\n }\n >,\n next: Entity,\n ) => {\n const entityURL = parseEntityURL(\n next?.metadata?.annotations?.['backstage.io/source-location'],\n );\n\n if (!entityURL) {\n return prev;\n }\n\n // NOTE: Find project based on Github URL\n const relatedProjects =\n projectSourceURL[`${entityURL?.host}${entityURL?.path}`]?.projectObjs;\n\n if (!relatedProjects) {\n return prev;\n }\n\n const entity = {\n path: entityURL.path,\n params: entityURL.params,\n namespace: next.metadata.namespace,\n kind: 'component',\n source: 'catalog',\n };\n\n relatedProjects.forEach(project => prev.push({ ...project, entity }));\n\n return prev;\n },\n [],\n );\n};\n\n/**\n * Extracts the source URL details from each project and returns a dictionary\n * where each key is a combination of the URL's host and pathname,\n * and the value is an object containing the original project and the parsed source URL data.\n *\n * @param projects Array of ProjectStatisticsSuccessResponseData\n * @returns A dictionary object with keys as `${host}${pathname}` strings extracted from sourceUrl and values as:\n * {\n * projectObjs: ProjectStatisticsSuccessResponseData[];\n sourceUrl: string | null;\n host: string | null;\n pathname: string | null;\n * }\n */\nexport function getSourceURLWiseProject(\n projects: ProjectStatisticsSuccessResponseData[],\n) {\n return projects.reduce(\n (acc, project) => {\n const projectTags = project.tags as Array<{ key: string; value: string }>;\n const sourceUrlTag = projectTags?.find(tag => tag.key === 'sourceUrl');\n let host = null;\n let pathname = null;\n let sourceUrl = null;\n\n if (sourceUrlTag && typeof sourceUrlTag.value === 'string') {\n sourceUrl = sourceUrlTag.value;\n const urlString = sourceUrl.startsWith('http')\n ? sourceUrl\n : `https://${sourceUrl}`;\n\n try {\n const urlObj = new URL(urlString);\n host = urlObj.host.toLocaleLowerCase();\n // Remove leading/trailing slashes and split\n pathname = urlObj.pathname;\n } catch (e) {\n // fallback: leave as nulls\n }\n }\n\n if (acc[`${host}${pathname}`]) {\n acc[`${host}${pathname}`].projectObjs.push(project);\n } else {\n acc[`${host}${pathname}`] = {\n projectObjs: [project],\n sourceUrl,\n host,\n pathname,\n };\n }\n return acc;\n },\n {} as Record<\n string,\n {\n projectObjs: ProjectStatisticsSuccessResponseData[];\n sourceUrl: string | null;\n host: string | null;\n pathname: string | null;\n }\n >,\n );\n}\n\nconst getIssueStatus = (\n engine: StatisticsEngine,\n finding:\n | CodeFindingSuccessResponseData\n | DependenciesFindingSuccessResponseData\n | ContainersFindingSuccessResponseData,\n): string => {\n if (engine === StatisticsEngine.CODE) {\n if ((finding as CodeFindingSuccessResponseData)?.suppressed)\n return 'suppressed';\n if (\n (finding as CodeFindingSuccessResponseData)?.almIssues?.jiraPlatform\n ?.issueStatus\n )\n return 'created';\n if ((finding as CodeFindingSuccessResponseData)?.reviewed)\n return 'reviewed';\n }\n\n if (engine === StatisticsEngine.DEPENDENCIES) {\n // NOTE: Available status: IGNORED and ACTIVE\n // ACTIVE means unreviewed\n // IGNORED means suppressed, comment fields are available to this status\n if (\n (finding as DependenciesFindingSuccessResponseData)?.findingInfo\n ?.status === 'IGNORED'\n )\n return 'suppressed';\n }\n\n return 'unreviewed';\n};\n\nexport const dataFindingParser = (\n code: CodeFindingSuccessResponseData[] = [],\n dependencies: DependenciesFindingSuccessResponseData[] = [],\n containers: ContainersFindingSuccessResponseData[] = [],\n projectName: string = '',\n) => {\n let codeFindings: Finding[] = [];\n let dependenciesFindings: Finding[] = [];\n let containersFindings: Finding[] = [];\n\n if (code.length) {\n codeFindings = code.map(finding => {\n return {\n kind: StatisticsEngine.CODE,\n level: finding.severity.toLowerCase() as StatisticsName,\n name: finding.type.cwe.title,\n origin: `${finding.sharedStep.file}:${finding.sharedStep.line}`,\n time: finding?.createdTime,\n projectId: finding.projectId,\n projectName: projectName,\n issue: {\n issueStatus: finding.almIssues.jiraPlatform.issueStatus,\n reporter: finding.almIssues.jiraPlatform.createdByName,\n creationDate: finding.almIssues.jiraPlatform.createdTime,\n ticketName: finding.almIssues.jiraPlatform.issueKey,\n link: `${finding.almIssues.jiraPlatform.publicLink}/browse/${finding.almIssues.jiraPlatform.issueKey}`,\n status: getIssueStatus(StatisticsEngine.CODE, finding),\n },\n };\n });\n }\n\n if (dependencies.length) {\n dependenciesFindings = dependencies.map(finding => {\n return {\n kind: StatisticsEngine.DEPENDENCIES,\n level: finding.vulnerability.severity.toLowerCase() as StatisticsName,\n name: finding.vulnerability.name,\n origin: finding.component.name,\n time: finding.vulnerability.modifiedDate,\n projectId: finding.project.uuid,\n projectName: projectName,\n issue: {\n issueStatus: '',\n reporter: '',\n creationDate: '',\n ticketName: '',\n link: '',\n status: getIssueStatus(StatisticsEngine.DEPENDENCIES, finding),\n },\n };\n });\n }\n\n if (containers.length) {\n containersFindings = containers.map(finding => {\n return {\n kind: StatisticsEngine.CONTAINERS,\n level: finding.severity.toLowerCase() as StatisticsName,\n name: finding.vulnerabilityId,\n origin: finding.packageName,\n time: finding.detectionDate,\n projectId: finding.projectUuid,\n projectName: projectName,\n issue: {\n issueStatus: '',\n reporter: '',\n creationDate: '',\n ticketName: '',\n link: '',\n status: getIssueStatus(StatisticsEngine.CONTAINERS, finding), // NOTE: Currently, issue for finding in containers no exist.\n },\n };\n });\n }\n\n const order: { [k: string]: number } = {\n critical: 1,\n high: 2,\n medium: 3,\n low: 4,\n };\n\n return [...codeFindings, ...dependenciesFindings, ...containersFindings].sort(\n (a, b) => {\n return order[a.level] - order[b.level];\n },\n );\n};\n\nconst parseQueryString = (href = '?'): QueryParams => {\n const [, queryString] = href.split('?');\n\n const queryParams: QueryParams = {};\n new URLSearchParams(queryString).forEach((val, key) => {\n queryParams[key] = val;\n });\n\n return queryParams;\n};\n\nexport const fetchQueryPagination = async <T>(cb: Function) => {\n const defaultQueryParams = { limit: '10000', cursor: '0' };\n const collection: T[] = [];\n\n const fetchLoop = async (queryParams: PaginationQueryParams) => {\n const result = await cb({ queryParams });\n\n collection.push(...result.response);\n\n const nextQuery = result.additionalData?.paging?.next;\n\n if (nextQuery) {\n const newQueryParams = parseQueryString(nextQuery);\n await fetchLoop(newQueryParams);\n }\n };\n\n await fetchLoop(defaultQueryParams);\n\n return collection;\n};\n"],"names":["StatisticsEngine","match","AZURE_HOST_NAME"],"mappings":";;;;;;AA4CO,MAAM,iBAAA,GAAoB,CAC/B,iBAAA,EAGA,oBAAA,KACG;AACH,EAAA,MAAM,gBAAA,GAAmB,oBAAA,CAAqB,MAAA,CAAO,CAAC,MAAM,IAAA,KAAS;AACnE,IAAA,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA;AAClB,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,EAAG,EAA+D,CAAA;AAElE,EAAA,MAAM,cAAc,iBAAA,CAAkB,MAAA;AAAA,IACpC,CACE,MACA,IAAA,KACG;AACH,MAAA,MAAM,oBAAA,GACJ,IAAA,CAAK,UAAA,CAAW,QAAA,oBAAyB,CACtC,+BAAA;AACL,MAAA,MAAM,gBAAA,GACJ,IAAA,CAAK,UAAA,CAAW,QAAA,oBAAyB,CAAE,2BAAA;AAC7C,MAAA,MAAM,kBAAA,GACJ,IAAA,CAAK,UAAA,CAAW,QAAA,oBAAyB,CACtC,6BAAA;AACL,MAAA,MAAM,eAAA,GACJ,IAAA,CAAK,UAAA,CAAW,QAAA,oBAAyB,CAAE,0BAAA;AAC7C,MAAA,MAAM,gBAAA,GACJ,oBAAA,GACA,gBAAA,GACA,kBAAA,GACA,eAAA;AAEF,MAAA,MAAM,QAAA,GACJ,IAAA,CAAK,UAAA,CAAW,kCAAA,YAAiB,CAAE,uBAAA;AACrC,MAAA,MAAM,UAAA,GACJ,IAAA,CAAK,UAAA,CAAW,kCAAA,YAAiB,CAAE,yBAAA;AACrC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,UAAA,CAAW,kCAAA,YAAiB,CAAE,sBAAA;AACnD,MAAA,MAAM,SAAA,GAAY,WAAW,UAAA,GAAa,OAAA;AAE1C,MAAA,MAAM,kBAAA,GACJ,IAAA,CAAK,UAAA,CAAW,cAAA,kBAAuB,CAAE,0BAAA;AAC3C,MAAA,MAAM,cAAA,GACJ,IAAA,CAAK,UAAA,CAAW,cAAA,kBAAuB,CAAE,sBAAA;AAC3C,MAAA,MAAM,gBAAA,GACJ,IAAA,CAAK,UAAA,CAAW,cAAA,kBAAuB,CAAE,wBAAA;AAC3C,MAAA,MAAM,aAAA,GACJ,IAAA,CAAK,UAAA,CAAW,cAAA,kBAAuB,CAAE,qBAAA;AAC3C,MAAA,MAAM,eAAA,GACJ,kBAAA,GAAqB,cAAA,GAAiB,gBAAA,GAAmB,aAAA;AAE3D,MAAA,MAAM,gBAAgB,oBAAA,GAAuB,kBAAA;AAC7C,MAAA,MAAM,SAAA,GAAY,mBAAmB,QAAA,GAAW,cAAA;AAChD,MAAA,MAAM,WAAA,GAAc,qBAAqB,UAAA,GAAa,gBAAA;AACtD,MAAA,MAAM,QAAA,GAAW,kBAAkB,OAAA,GAAU,aAAA;AAC7C,MAAA,MAAM,KAAA,GAAQ,mBAAmB,SAAA,GAAY,eAAA;AAE7C,MAAA,MAAM,UAAA,GAAa;AAAA,QACjB,CAACA,mCAAA,CAAiB,YAAY,GAAG;AAAA,UAC/B,QAAA,EAAU,oBAAA;AAAA,UACV,IAAA,EAAM,gBAAA;AAAA,UACN,MAAA,EAAQ,kBAAA;AAAA,UACR,GAAA,EAAK,eAAA;AAAA,UACL,KAAA,EAAO;AAAA,SACT;AAAA,QACA,CAACA,mCAAA,CAAiB,IAAI,GAAG;AAAA,UACvB,QAAA,EAAU,IAAA;AAAA,UACV,IAAA,EAAM,QAAA;AAAA,UACN,MAAA,EAAQ,UAAA;AAAA,UACR,GAAA,EAAK,OAAA;AAAA,UACL,KAAA,EAAO;AAAA,SACT;AAAA,QACA,CAACA,mCAAA,CAAiB,UAAU,GAAG;AAAA,UAC7B,QAAA,EAAU,kBAAA;AAAA,UACV,IAAA,EAAM,cAAA;AAAA,UACN,MAAA,EAAQ,gBAAA;AAAA,UACR,GAAA,EAAK,aAAA;AAAA,UACL,KAAA,EAAO;AAAA,SACT;AAAA,QACA,QAAA,EAAU,aAAA;AAAA,QACV,IAAA,EAAM,SAAA;AAAA,QACN,MAAA,EAAQ,WAAA;AAAA,QACR,GAAA,EAAK,QAAA;AAAA,QACL;AAAA,OACF;AAEA,MAAA,MAAM,OAAA,GAAU;AAAA,QACd,UAAA;AAAA,QACA,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,QAAQ,IAAA,CAAK,MAAA;AAAA,QACb,eAAA,EAAiB,gBAAA,CAAiB,IAAA,CAAK,IAAI,CAAA,CAAE,eAAA;AAAA,QAC7C,iBAAiB,IAAA,CAAK,eAAA;AAAA,QACtB,QAAA,EAAU,IAAA,CAAK,UAAA,CAAW,WAAA,iBAAsB,CAAE,YAAA;AAAA,QAClD,SAAA,EAAW,KAAK,UAAA,EAAY,sBAAA,GACxB,OAAO,OAAA,CAAQ,IAAA,CAAK,UAAA,CAAW,sBAAsB,CAAA,CAAE,IAAA;AAAA,UACrD,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,CAAC,CAAA,GAAI,EAAE,CAAC;AAAA,YAErB;AAAC,OACR;AAEA,MAAA,IAAA,CAAK,WAAA,CAAY,QAAQ,OAAO,CAAA;AAChC,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA;AAAA,MACE,aAAa;AAAC;AAChB,GACF;AAEA,EAAA,WAAA,CAAY,WAAA,CAAY,IAAA;AAAA,IACtB,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,UAAA,CAAW,QAAA,GAAW,EAAE,UAAA,CAAW;AAAA,GACjD;AAEA,EAAA,OAAO,WAAA;AACT;AAEO,MAAM,cAAA,GAAiB,CAAC,SAAA,KAAuB;AACpD,EAAA,IAAI;AACF,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,UAAU,SAAA,CAAU,KAAA;AAAA,MACxB;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA;AAC9B,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,IAAA,CAAK,WAAA,EAAY;AACtC,IAAA,IAAI,UAAUC,kBAAA,CAAM,aAAA,EAAe,EAAE,GAAA,EAAK,OAAO,CAAA;AAEjD,IAAA,IAAI,aAAaC,yBAAA,EAAiB;AAChC,MAAA,OAAA,GAAUD,kBAAA,CAAM,2BAAA,EAA6B,EAAE,GAAA,EAAK,OAAO,CAAA;AAAA,IAC7D;AACA,IAAA,MAAM,gBAAA,GAAmB,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AAC7C,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,OAAO,EAAE,GAAG,gBAAA,EAAkB,IAAA,EAAM,QAAA,EAAS;AAAA,IAC/C;AACA,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,MAAM,WAAA,GAAc,CACzB,QAAA,EACA,QAAA,KACG;AACH,EAAA,MAAM,gBAAA,GAAmB,wBAAwB,QAAQ,CAAA;AACzD,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CACE,MAKA,IAAA,KACG;AACH,MAAA,MAAM,SAAA,GAAY,cAAA;AAAA,QAChB,IAAA,EAAM,QAAA,EAAU,WAAA,GAAc,8BAA8B;AAAA,OAC9D;AAEA,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,OAAO,IAAA;AAAA,MACT;AAGA,MAAA,MAAM,eAAA,GACJ,iBAAiB,CAAA,EAAG,SAAA,EAAW,IAAI,CAAA,EAAG,SAAA,EAAW,IAAI,CAAA,CAAE,CAAA,EAAG,WAAA;AAE5D,MAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,QAAA,OAAO,IAAA;AAAA,MACT;AAEA,MAAA,MAAM,MAAA,GAAS;AAAA,QACb,MAAM,SAAA,CAAU,IAAA;AAAA,QAChB,QAAQ,SAAA,CAAU,MAAA;AAAA,QAClB,SAAA,EAAW,KAAK,QAAA,CAAS,SAAA;AAAA,QACzB,IAAA,EAAM,WAAA;AAAA,QACN,MAAA,EAAQ;AAAA,OACV;AAEA,MAAA,eAAA,CAAgB,OAAA,CAAQ,aAAW,IAAA,CAAK,IAAA,CAAK,EAAE,GAAG,OAAA,EAAS,MAAA,EAAQ,CAAC,CAAA;AAEpE,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA;AAAC,GACH;AACF;AAgBO,SAAS,wBACd,QAAA,EACA;AACA,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CAAC,KAAK,OAAA,KAAY;AAChB,MAAA,MAAM,cAAc,OAAA,CAAQ,IAAA;AAC5B,MAAA,MAAM,eAAe,WAAA,EAAa,IAAA,CAAK,CAAA,GAAA,KAAO,GAAA,CAAI,QAAQ,WAAW,CAAA;AACrE,MAAA,IAAI,IAAA,GAAO,IAAA;AACX,MAAA,IAAI,QAAA,GAAW,IAAA;AACf,MAAA,IAAI,SAAA,GAAY,IAAA;AAEhB,MAAA,IAAI,YAAA,IAAgB,OAAO,YAAA,CAAa,KAAA,KAAU,QAAA,EAAU;AAC1D,QAAA,SAAA,GAAY,YAAA,CAAa,KAAA;AACzB,QAAA,MAAM,YAAY,SAAA,CAAU,UAAA,CAAW,MAAM,CAAA,GACzC,SAAA,GACA,WAAW,SAAS,CAAA,CAAA;AAExB,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,SAAS,CAAA;AAChC,UAAA,IAAA,GAAO,MAAA,CAAO,KAAK,iBAAA,EAAkB;AAErC,UAAA,QAAA,GAAW,MAAA,CAAO,QAAA;AAAA,QACpB,SAAS,CAAA,EAAG;AAAA,QAEZ;AAAA,MACF;AAEA,MAAA,IAAI,IAAI,CAAA,EAAG,IAAI,CAAA,EAAG,QAAQ,EAAE,CAAA,EAAG;AAC7B,QAAA,GAAA,CAAI,CAAA,EAAG,IAAI,CAAA,EAAG,QAAQ,EAAE,CAAA,CAAE,WAAA,CAAY,KAAK,OAAO,CAAA;AAAA,MACpD,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,CAAA,EAAG,IAAI,CAAA,EAAG,QAAQ,EAAE,CAAA,GAAI;AAAA,UAC1B,WAAA,EAAa,CAAC,OAAO,CAAA;AAAA,UACrB,SAAA;AAAA,UACA,IAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,OAAO,GAAA;AAAA,IACT,CAAA;AAAA,IACA;AAAC,GASH;AACF;AAEA,MAAM,cAAA,GAAiB,CACrB,MAAA,EACA,OAAA,KAIW;AACX,EAAA,IAAI,MAAA,KAAWD,oCAAiB,IAAA,EAAM;AACpC,IAAA,IAAK,OAAA,EAA4C,UAAA;AAC/C,MAAA,OAAO,YAAA;AACT,IAAA,IACG,OAAA,EAA4C,WAAW,YAAA,EACpD,WAAA;AAEJ,MAAA,OAAO,SAAA;AACT,IAAA,IAAK,OAAA,EAA4C,QAAA;AAC/C,MAAA,OAAO,UAAA;AAAA,EACX;AAEA,EAAA,IAAI,MAAA,KAAWA,oCAAiB,YAAA,EAAc;AAI5C,IAAA,IACG,OAAA,EAAoD,aACjD,MAAA,KAAW,SAAA;AAEf,MAAA,OAAO,YAAA;AAAA,EACX;AAEA,EAAA,OAAO,YAAA;AACT,CAAA;AAEO,MAAM,iBAAA,GAAoB,CAC/B,IAAA,GAAyC,EAAC,EAC1C,YAAA,GAAyD,EAAC,EAC1D,UAAA,GAAqD,EAAC,EACtD,WAAA,GAAsB,EAAA,KACnB;AACH,EAAA,IAAI,eAA0B,EAAC;AAC/B,EAAA,IAAI,uBAAkC,EAAC;AACvC,EAAA,IAAI,qBAAgC,EAAC;AAErC,EAAA,IAAI,KAAK,MAAA,EAAQ;AACf,IAAA,YAAA,GAAe,IAAA,CAAK,IAAI,CAAA,OAAA,KAAW;AACjC,MAAA,OAAO;AAAA,QACL,MAAMA,mCAAA,CAAiB,IAAA;AAAA,QACvB,KAAA,EAAO,OAAA,CAAQ,QAAA,CAAS,WAAA,EAAY;AAAA,QACpC,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,GAAA,CAAI,KAAA;AAAA,QACvB,MAAA,EAAQ,GAAG,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAA,CAAA,EAAI,OAAA,CAAQ,WAAW,IAAI,CAAA,CAAA;AAAA,QAC7D,MAAM,OAAA,EAAS,WAAA;AAAA,QACf,WAAW,OAAA,CAAQ,SAAA;AAAA,QACnB,WAAA;AAAA,QACA,KAAA,EAAO;AAAA,UACL,WAAA,EAAa,OAAA,CAAQ,SAAA,CAAU,YAAA,CAAa,WAAA;AAAA,UAC5C,QAAA,EAAU,OAAA,CAAQ,SAAA,CAAU,YAAA,CAAa,aAAA;AAAA,UACzC,YAAA,EAAc,OAAA,CAAQ,SAAA,CAAU,YAAA,CAAa,WAAA;AAAA,UAC7C,UAAA,EAAY,OAAA,CAAQ,SAAA,CAAU,YAAA,CAAa,QAAA;AAAA,UAC3C,IAAA,EAAM,CAAA,EAAG,OAAA,CAAQ,SAAA,CAAU,YAAA,CAAa,UAAU,CAAA,QAAA,EAAW,OAAA,CAAQ,SAAA,CAAU,YAAA,CAAa,QAAQ,CAAA,CAAA;AAAA,UACpG,MAAA,EAAQ,cAAA,CAAeA,mCAAA,CAAiB,IAAA,EAAM,OAAO;AAAA;AACvD,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,aAAa,MAAA,EAAQ;AACvB,IAAA,oBAAA,GAAuB,YAAA,CAAa,IAAI,CAAA,OAAA,KAAW;AACjD,MAAA,OAAO;AAAA,QACL,MAAMA,mCAAA,CAAiB,YAAA;AAAA,QACvB,KAAA,EAAO,OAAA,CAAQ,aAAA,CAAc,QAAA,CAAS,WAAA,EAAY;AAAA,QAClD,IAAA,EAAM,QAAQ,aAAA,CAAc,IAAA;AAAA,QAC5B,MAAA,EAAQ,QAAQ,SAAA,CAAU,IAAA;AAAA,QAC1B,IAAA,EAAM,QAAQ,aAAA,CAAc,YAAA;AAAA,QAC5B,SAAA,EAAW,QAAQ,OAAA,CAAQ,IAAA;AAAA,QAC3B,WAAA;AAAA,QACA,KAAA,EAAO;AAAA,UACL,WAAA,EAAa,EAAA;AAAA,UACb,QAAA,EAAU,EAAA;AAAA,UACV,YAAA,EAAc,EAAA;AAAA,UACd,UAAA,EAAY,EAAA;AAAA,UACZ,IAAA,EAAM,EAAA;AAAA,UACN,MAAA,EAAQ,cAAA,CAAeA,mCAAA,CAAiB,YAAA,EAAc,OAAO;AAAA;AAC/D,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,WAAW,MAAA,EAAQ;AACrB,IAAA,kBAAA,GAAqB,UAAA,CAAW,IAAI,CAAA,OAAA,KAAW;AAC7C,MAAA,OAAO;AAAA,QACL,MAAMA,mCAAA,CAAiB,UAAA;AAAA,QACvB,KAAA,EAAO,OAAA,CAAQ,QAAA,CAAS,WAAA,EAAY;AAAA,QACpC,MAAM,OAAA,CAAQ,eAAA;AAAA,QACd,QAAQ,OAAA,CAAQ,WAAA;AAAA,QAChB,MAAM,OAAA,CAAQ,aAAA;AAAA,QACd,WAAW,OAAA,CAAQ,WAAA;AAAA,QACnB,WAAA;AAAA,QACA,KAAA,EAAO;AAAA,UACL,WAAA,EAAa,EAAA;AAAA,UACb,QAAA,EAAU,EAAA;AAAA,UACV,YAAA,EAAc,EAAA;AAAA,UACd,UAAA,EAAY,EAAA;AAAA,UACZ,IAAA,EAAM,EAAA;AAAA,UACN,MAAA,EAAQ,cAAA,CAAeA,mCAAA,CAAiB,UAAA,EAAY,OAAO;AAAA;AAAA;AAC7D,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,KAAA,GAAiC;AAAA,IACrC,QAAA,EAAU,CAAA;AAAA,IACV,IAAA,EAAM,CAAA;AAAA,IACN,MAAA,EAAQ,CAAA;AAAA,IACR,GAAA,EAAK;AAAA,GACP;AAEA,EAAA,OAAO,CAAC,GAAG,YAAA,EAAc,GAAG,oBAAA,EAAsB,GAAG,kBAAkB,CAAA,CAAE,IAAA;AAAA,IACvE,CAAC,GAAG,CAAA,KAAM;AACR,MAAA,OAAO,MAAM,CAAA,CAAE,KAAK,CAAA,GAAI,KAAA,CAAM,EAAE,KAAK,CAAA;AAAA,IACvC;AAAA,GACF;AACF;AAEA,MAAM,gBAAA,GAAmB,CAAC,IAAA,GAAO,GAAA,KAAqB;AACpD,EAAA,MAAM,GAAG,WAAW,CAAA,GAAI,IAAA,CAAK,MAAM,GAAG,CAAA;AAEtC,EAAA,MAAM,cAA2B,EAAC;AAClC,EAAA,IAAI,gBAAgB,WAAW,CAAA,CAAE,OAAA,CAAQ,CAAC,KAAK,GAAA,KAAQ;AACrD,IAAA,WAAA,CAAY,GAAG,CAAA,GAAI,GAAA;AAAA,EACrB,CAAC,CAAA;AAED,EAAA,OAAO,WAAA;AACT,CAAA;AAEO,MAAM,oBAAA,GAAuB,OAAU,EAAA,KAAiB;AAC7D,EAAA,MAAM,kBAAA,GAAqB,EAAE,KAAA,EAAO,OAAA,EAAS,QAAQ,GAAA,EAAI;AACzD,EAAA,MAAM,aAAkB,EAAC;AAEzB,EAAA,MAAM,SAAA,GAAY,OAAO,WAAA,KAAuC;AAC9D,IAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,EAAE,aAAa,CAAA;AAEvC,IAAA,UAAA,CAAW,IAAA,CAAK,GAAG,MAAA,CAAO,QAAQ,CAAA;AAElC,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,cAAA,EAAgB,MAAA,EAAQ,IAAA;AAEjD,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAM,cAAA,GAAiB,iBAAiB,SAAS,CAAA;AACjD,MAAA,MAAM,UAAU,cAAc,CAAA;AAAA,IAChC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAU,kBAAkB,CAAA;AAElC,EAAA,OAAO,UAAA;AACT;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"data.service.types.cjs.js","sources":["../../src/service/data.service.types.ts"],"sourcesContent":["export type PaginationQueryParams = {\n cursor?: string;\n limit?: string;\n};\n\ntype PaginationSuccessResponseData = {\n additionalData: {\n totalItems: number;\n paging: {\n next?: string;\n };\n };\n};\n\ntype BodyParams = {\n projectUuids?: string[];\n applicationUuid?: string[];\n};\n\ntype PathParams = {\n uuid: string;\n};\n\nexport type GetOrganizationProjectRequestData = {\n queryParams?: PaginationQueryParams;\n};\n\nexport type OrganizationProjectSuccessResponseData = {\n uuid: string;\n name: string;\n path: string;\n applicationName: string;\n applicationUuid: string;\n};\n\nexport type GetOrganizationProjectSuccessResponseData = {\n supportToken: string;\n response: OrganizationProjectSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type GetProjectStatisticsRequestData = {\n queryParams?: PaginationQueryParams;\n bodyParams?: BodyParams;\n};\n\nexport type ProjectStatisticsSuccessResponseData = {\n uuid: string;\n name: string;\n path: string;\n applicationUuid: string;\n creationDate: string;\n tags: [];\n labels: [];\n statistics: {\n UNIFIED_VULNERABILITIES: {\n unifiedCriticalVulnerabilities: number;\n unifiedHighVulnerabilities: number;\n unifiedMediumVulnerabilities: number;\n unifiedLowVulnerabilities: number;\n unifiedVulnerabilities: number;\n };\n VULNERABILITY_EFFECTIVENESS: {};\n LIBRARY_TYPE_HISTOGRAM: Record<string, number>;\n IMG_USAGE: {};\n POLICY_VIOLATION_LIBRARIES: {\n policyViolatingLibraries: number;\n };\n SAST_VULNERABILITIES_BY_TYPE: Record<string, number>;\n GENERAL: {\n totalLibraries: number;\n };\n LLM_SECURITY: {\n llmTotalLines: number;\n };\n IMG_SECURITY: {\n imgCriticalVulnerabilities: number;\n imgMaxRiskScore: number;\n imgMediumVulnerabilities: number;\n imgLowVulnerabilities: number;\n imgSecretMediumVulnerabilities: number;\n imgUnknownVulnerabilities: number;\n imgSecretHighVulnerabilities: number;\n imgTotalVulnerabilities: number;\n imgHighVulnerabilities: number;\n imgSecretCriticalVulnerabilities: number;\n imgSecretLowVulnerabilities: number;\n };\n ALERTS: {\n criticalSeverityVulnerabilities: number;\n highSeverityVulnerabilities: number;\n vulnerableLibraries: number;\n mediumSeverityVulnerabilities: number;\n lowSeverityVulnerabilities: number;\n };\n OUTDATED_LIBRARIES: {\n outdatedLibraries: number;\n };\n POLICY_VIOLATIONS: {};\n SAST_SCAN: {\n sastTotalLines: number;\n sastTestedFiles: number;\n sastTotalFiles: number;\n sastTestedLines: number;\n sastTotalMended: number;\n sastTotalRemediations: number;\n };\n VULNERABILITY_SEVERITY_LIBRARIES: {\n lowSeverityLibraries: number;\n highSeverityLibraries: number;\n mediumSeverityLibraries: number;\n criticalSeverityLibraries: number;\n };\n LICENSE_RISK: {\n highRiskLicenses: number;\n mediumRiskLicenses: number;\n lowRiskLicenses: number;\n };\n IAC_SECURITY: {\n iacCriticalMisconfigurations: number;\n iacHighMisconfigurations: number;\n iacTotalMisconfigurations: number;\n iacLowMisconfigurations: number;\n iacMediumMisconfigurations: number;\n };\n SCA_SECURITY: {};\n LICENSE_HISTOGRAM: Record<string, number>;\n SAST_VULNERABILITIES_BY_SEVERITY: {\n sastVulnerabilities: number;\n sastHighVulnerabilities: number;\n sastMediumVulnerabilities: number;\n sastLowVulnerabilities: number;\n };\n LAST_SCAN: {\n lastScanTime: number;\n lastScaScanTime: number;\n lastImgScanTime: number;\n lastSastScanTime: number;\n };\n };\n};\n\nexport type GetProjectStatisticsSuccessResponseData = {\n supportToken: string;\n response: ProjectStatisticsSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type EntityURL = {\n path: string;\n params: {\n org?: string;\n repo?: string;\n };\n namespace?: string;\n kind: string;\n source: string;\n};\n\nexport enum StatisticsName {\n CRITICAL = 'critical',\n HIGH = 'high',\n MEDIUM = 'medium',\n LOW = 'low',\n TOTAL = 'total',\n}\n\nexport enum StatisticsEngine {\n DEPENDENCIES = 'dependencies',\n CODE = 'code',\n CONTAINERS = 'containers',\n}\n\ntype StatisticsBase = {\n [StatisticsName.CRITICAL]: number;\n [StatisticsName.HIGH]: number;\n [StatisticsName.MEDIUM]: number;\n [StatisticsName.LOW]: number;\n [StatisticsName.TOTAL]: number;\n};\n\nexport type Statistics = {\n [StatisticsEngine.DEPENDENCIES]: StatisticsBase;\n [StatisticsEngine.CODE]: Omit<StatisticsBase, StatisticsName.CRITICAL> & {\n [StatisticsName.CRITICAL]: null;\n };\n [StatisticsEngine.CONTAINERS]: StatisticsBase;\n} & StatisticsBase;\n\nexport type Project = {\n statistics: Statistics;\n uuid: string;\n name: string;\n path: string;\n applicationName: string;\n applicationUuid: string;\n lastScan: number;\n languages: Array<[string, number]>;\n entity: EntityURL;\n};\n\n// Code Finding API Data\ntype CodeFindingDataFlowSuccessResponseData = {\n id: string;\n sink: string;\n sinkKind: string;\n sinkFile: string;\n sinkSnippet: string;\n sinkLine: number;\n inputSource: string;\n inputKind: string;\n inputFlow: [\n {\n name: string;\n kind: string;\n file: string;\n snippet: string;\n line: number;\n startLine: number;\n endLine: number;\n },\n ];\n functionCalls: [\n {\n name: string;\n kind: string;\n file: string;\n snippet: string;\n line: number;\n startLine: number;\n endLine: number;\n },\n ];\n filter: {\n isFiltered: boolean;\n filterTypes: unknown[];\n };\n isNew: boolean;\n rating: number;\n confidenceRating: number;\n ageRating: number;\n};\n\nexport type CodeFindingSuccessResponseData = {\n id: string;\n scanId: string;\n snapshotId: string;\n projectId: string;\n appId: string;\n type: {\n id: number;\n name: string;\n engineId: number;\n language: string;\n sarif: string;\n sarifLevel: string;\n order: number;\n severity: StatisticsName;\n severityRating: number;\n description: string;\n recommendations: [string];\n references: [string];\n cwe: {\n id: string;\n title: string;\n url: string;\n };\n pcidss: {\n section: string;\n title: string;\n };\n nist: {\n control: string;\n priority: string;\n title: string;\n url: string;\n };\n hipaa: {\n control: string;\n title: string;\n };\n hitrust: {\n control: string;\n title: string;\n };\n owasp: {\n index: string;\n title: string;\n url: string;\n };\n owasp2021: {\n index: string;\n title: string;\n url: string;\n };\n capec: {\n id: string;\n title: string;\n url: string;\n };\n sansTop25: {\n rank: number;\n title: string;\n };\n };\n description: string;\n createdTime: string;\n isNew: boolean;\n severity: StatisticsName;\n baseline: boolean;\n hasRemediation: boolean;\n suppressed: boolean;\n suppressedBy: string;\n suppressionTime: string;\n suppressionMessage: string;\n reviewed: boolean;\n IssueStatus: number;\n sharedStep: {\n name: string;\n kind: string;\n file: string;\n snippet: string;\n line: number;\n startLine: number;\n endLine: number;\n lineBlame: {\n commitId: string;\n file: string;\n line: number;\n };\n };\n dataFlows: CodeFindingDataFlowSuccessResponseData[];\n severityRating: number;\n confidenceRating: number;\n ageRating: number;\n rating: number;\n almIssues: {\n jira: {\n issueId: string;\n project: string;\n };\n azure: {\n workItemId: number;\n project: string;\n };\n jiraPlatform: {\n internalStatus: string;\n issueStatus: string;\n issueKey: string;\n publicLink: string;\n createdTime: string;\n createdBy: string;\n createdByName: string;\n };\n };\n comments: unknown[];\n};\n\nexport type GetCodeFindingSuccessResponseData = {\n response: CodeFindingSuccessResponseData[];\n supportToken: string;\n} & PaginationSuccessResponseData;\n\nexport type GetCodeFindingsRequestData = {\n queryParams?: PaginationQueryParams;\n pathParams: PathParams;\n};\n\n// Dependencies Finding API Data\nexport type DependenciesFindingSuccessResponseData = {\n uuid: string;\n name: string;\n type: string;\n component: {\n uuid: string;\n name: string;\n description: string;\n componentType: string;\n libraryType: string;\n rootLibrary: boolean;\n references: {\n url: string;\n homePage: string;\n genericPackageIndex: string;\n };\n groupId: string;\n artifactId: string;\n version: string;\n path: string;\n };\n findingInfo: {\n status: string;\n comment: unknown;\n detectedAt: string;\n modifiedAt: string;\n };\n project: {\n uuid: string;\n name: string;\n path: string;\n applicationUuid: string;\n };\n application: {\n uuid: string;\n name: string;\n };\n vulnerability: {\n name: string;\n type: string;\n description: string;\n score: number;\n severity: StatisticsName;\n publishDate: string;\n modifiedDate: string;\n vulnerabilityScoring: {\n score: number;\n severity: string;\n type: string;\n }[];\n };\n topFix: {\n id: number;\n vulnerability: string;\n type: string;\n origin: string;\n url: string;\n fixResolution: string;\n date: string;\n message: string;\n };\n effective: string;\n threatAssessment: {\n exploitCodeMaturity: string;\n epssPercentage: number;\n };\n exploitable: boolean;\n scoreMetadataVector: string;\n};\n\nexport type GetDependenciesFindingSuccessResponseData = {\n supportToken: string;\n response: DependenciesFindingSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type GetDependenciesFindingsRequestData = {\n queryParams?: PaginationQueryParams;\n pathParams: PathParams;\n};\n\n// Containers Finding API Data\nexport type ContainersFindingSuccessResponseData = {\n uuid: string;\n vulnerabilityId: string;\n description: string;\n projectUuid: string;\n imageName: string;\n packageName: string;\n packageVersion: string;\n severity: StatisticsName;\n cvss: number;\n epss: number;\n hasFix: false;\n fixVersion: string;\n publishedDate: string;\n detectionDate: string;\n};\n\nexport type GetContainersFindingSuccessResponseData = {\n supportToken: string;\n response: ContainersFindingSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type GetContainersFindingsRequestData = {\n queryParams?: PaginationQueryParams;\n pathParams: PathParams;\n};\n\nexport type Finding = {\n kind: StatisticsEngine;\n level: StatisticsName;\n name: string;\n origin: string;\n time: string;\n projectId: string;\n projectName: string;\n issue: {\n issueStatus: string;\n reporter: string;\n creationDate: string;\n ticketName: string;\n link: string;\n status: string;\n };\n};\n"],"names":["StatisticsEngine"],"mappings":";;AAqKY,IAAA,gBAAA,qBAAAA,iBAAL,KAAA;AACL,EAAAA,kBAAA,cAAe,CAAA,GAAA,cAAA;AACf,EAAAA,kBAAA,MAAO,CAAA,GAAA,MAAA;AACP,EAAAA,kBAAA,YAAa,CAAA,GAAA,YAAA;AAHH,EAAAA,OAAAA,iBAAAA;AAAA,CAAA,EAAA,gBAAA,IAAA,EAAA;;;;"}
1
+ {"version":3,"file":"data.service.types.cjs.js","sources":["../../src/service/data.service.types.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport type PaginationQueryParams = {\n cursor?: string;\n limit?: string;\n};\n\ntype PaginationSuccessResponseData = {\n additionalData: {\n totalItems: number;\n paging: {\n next?: string;\n };\n };\n};\n\ntype BodyParams = {\n projectUuids?: string[];\n applicationUuid?: string[];\n};\n\ntype PathParams = {\n uuid: string;\n};\n\nexport type GetOrganizationProjectRequestData = {\n queryParams?: PaginationQueryParams;\n};\n\nexport type OrganizationProjectSuccessResponseData = {\n uuid: string;\n name: string;\n path: string;\n applicationName: string;\n applicationUuid: string;\n};\n\nexport type GetOrganizationProjectSuccessResponseData = {\n supportToken: string;\n response: OrganizationProjectSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type GetProjectStatisticsRequestData = {\n queryParams?: PaginationQueryParams;\n bodyParams?: BodyParams;\n};\n\nexport type ProjectStatisticsSuccessResponseData = {\n uuid: string;\n name: string;\n path: string;\n applicationUuid: string;\n creationDate: string;\n tags: [];\n labels: [];\n statistics: {\n UNIFIED_VULNERABILITIES: {\n unifiedCriticalVulnerabilities: number;\n unifiedHighVulnerabilities: number;\n unifiedMediumVulnerabilities: number;\n unifiedLowVulnerabilities: number;\n unifiedVulnerabilities: number;\n };\n VULNERABILITY_EFFECTIVENESS: {};\n LIBRARY_TYPE_HISTOGRAM: Record<string, number>;\n IMG_USAGE: {};\n POLICY_VIOLATION_LIBRARIES: {\n policyViolatingLibraries: number;\n };\n SAST_VULNERABILITIES_BY_TYPE: Record<string, number>;\n GENERAL: {\n totalLibraries: number;\n };\n LLM_SECURITY: {\n llmTotalLines: number;\n };\n IMG_SECURITY: {\n imgCriticalVulnerabilities: number;\n imgMaxRiskScore: number;\n imgMediumVulnerabilities: number;\n imgLowVulnerabilities: number;\n imgSecretMediumVulnerabilities: number;\n imgUnknownVulnerabilities: number;\n imgSecretHighVulnerabilities: number;\n imgTotalVulnerabilities: number;\n imgHighVulnerabilities: number;\n imgSecretCriticalVulnerabilities: number;\n imgSecretLowVulnerabilities: number;\n };\n ALERTS: {\n criticalSeverityVulnerabilities: number;\n highSeverityVulnerabilities: number;\n vulnerableLibraries: number;\n mediumSeverityVulnerabilities: number;\n lowSeverityVulnerabilities: number;\n };\n OUTDATED_LIBRARIES: {\n outdatedLibraries: number;\n };\n POLICY_VIOLATIONS: {};\n SAST_SCAN: {\n sastTotalLines: number;\n sastTestedFiles: number;\n sastTotalFiles: number;\n sastTestedLines: number;\n sastTotalMended: number;\n sastTotalRemediations: number;\n };\n VULNERABILITY_SEVERITY_LIBRARIES: {\n lowSeverityLibraries: number;\n highSeverityLibraries: number;\n mediumSeverityLibraries: number;\n criticalSeverityLibraries: number;\n };\n LICENSE_RISK: {\n highRiskLicenses: number;\n mediumRiskLicenses: number;\n lowRiskLicenses: number;\n };\n IAC_SECURITY: {\n iacCriticalMisconfigurations: number;\n iacHighMisconfigurations: number;\n iacTotalMisconfigurations: number;\n iacLowMisconfigurations: number;\n iacMediumMisconfigurations: number;\n };\n SCA_SECURITY: {};\n LICENSE_HISTOGRAM: Record<string, number>;\n SAST_VULNERABILITIES_BY_SEVERITY: {\n sastVulnerabilities: number;\n sastHighVulnerabilities: number;\n sastMediumVulnerabilities: number;\n sastLowVulnerabilities: number;\n };\n LAST_SCAN: {\n lastScanTime: number;\n lastScaScanTime: number;\n lastImgScanTime: number;\n lastSastScanTime: number;\n };\n };\n};\n\nexport type GetProjectStatisticsSuccessResponseData = {\n supportToken: string;\n response: ProjectStatisticsSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type EntityURL = {\n path: string;\n params: {\n org?: string;\n repo?: string;\n };\n namespace?: string;\n kind: string;\n source: string;\n};\n\nexport enum StatisticsName {\n CRITICAL = 'critical',\n HIGH = 'high',\n MEDIUM = 'medium',\n LOW = 'low',\n TOTAL = 'total',\n}\n\nexport enum StatisticsEngine {\n DEPENDENCIES = 'dependencies',\n CODE = 'code',\n CONTAINERS = 'containers',\n}\n\ntype StatisticsBase = {\n [StatisticsName.CRITICAL]: number;\n [StatisticsName.HIGH]: number;\n [StatisticsName.MEDIUM]: number;\n [StatisticsName.LOW]: number;\n [StatisticsName.TOTAL]: number;\n};\n\nexport type Statistics = {\n [StatisticsEngine.DEPENDENCIES]: StatisticsBase;\n [StatisticsEngine.CODE]: Omit<StatisticsBase, StatisticsName.CRITICAL> & {\n [StatisticsName.CRITICAL]: null;\n };\n [StatisticsEngine.CONTAINERS]: StatisticsBase;\n} & StatisticsBase;\n\nexport type Project = {\n statistics: Statistics;\n uuid: string;\n name: string;\n path: string;\n applicationName: string;\n applicationUuid: string;\n lastScan: number;\n languages: Array<[string, number]>;\n entity: EntityURL;\n};\n\n// Code Finding API Data\ntype CodeFindingDataFlowSuccessResponseData = {\n id: string;\n sink: string;\n sinkKind: string;\n sinkFile: string;\n sinkSnippet: string;\n sinkLine: number;\n inputSource: string;\n inputKind: string;\n inputFlow: [\n {\n name: string;\n kind: string;\n file: string;\n snippet: string;\n line: number;\n startLine: number;\n endLine: number;\n },\n ];\n functionCalls: [\n {\n name: string;\n kind: string;\n file: string;\n snippet: string;\n line: number;\n startLine: number;\n endLine: number;\n },\n ];\n filter: {\n isFiltered: boolean;\n filterTypes: unknown[];\n };\n isNew: boolean;\n rating: number;\n confidenceRating: number;\n ageRating: number;\n};\n\nexport type CodeFindingSuccessResponseData = {\n id: string;\n scanId: string;\n snapshotId: string;\n projectId: string;\n appId: string;\n type: {\n id: number;\n name: string;\n engineId: number;\n language: string;\n sarif: string;\n sarifLevel: string;\n order: number;\n severity: StatisticsName;\n severityRating: number;\n description: string;\n recommendations: [string];\n references: [string];\n cwe: {\n id: string;\n title: string;\n url: string;\n };\n pcidss: {\n section: string;\n title: string;\n };\n nist: {\n control: string;\n priority: string;\n title: string;\n url: string;\n };\n hipaa: {\n control: string;\n title: string;\n };\n hitrust: {\n control: string;\n title: string;\n };\n owasp: {\n index: string;\n title: string;\n url: string;\n };\n owasp2021: {\n index: string;\n title: string;\n url: string;\n };\n capec: {\n id: string;\n title: string;\n url: string;\n };\n sansTop25: {\n rank: number;\n title: string;\n };\n };\n description: string;\n createdTime: string;\n isNew: boolean;\n severity: StatisticsName;\n baseline: boolean;\n hasRemediation: boolean;\n suppressed: boolean;\n suppressedBy: string;\n suppressionTime: string;\n suppressionMessage: string;\n reviewed: boolean;\n IssueStatus: number;\n sharedStep: {\n name: string;\n kind: string;\n file: string;\n snippet: string;\n line: number;\n startLine: number;\n endLine: number;\n lineBlame: {\n commitId: string;\n file: string;\n line: number;\n };\n };\n dataFlows: CodeFindingDataFlowSuccessResponseData[];\n severityRating: number;\n confidenceRating: number;\n ageRating: number;\n rating: number;\n almIssues: {\n jira: {\n issueId: string;\n project: string;\n };\n azure: {\n workItemId: number;\n project: string;\n };\n jiraPlatform: {\n internalStatus: string;\n issueStatus: string;\n issueKey: string;\n publicLink: string;\n createdTime: string;\n createdBy: string;\n createdByName: string;\n };\n };\n comments: unknown[];\n};\n\nexport type GetCodeFindingSuccessResponseData = {\n response: CodeFindingSuccessResponseData[];\n supportToken: string;\n} & PaginationSuccessResponseData;\n\nexport type GetCodeFindingsRequestData = {\n queryParams?: PaginationQueryParams;\n pathParams: PathParams;\n};\n\n// Dependencies Finding API Data\nexport type DependenciesFindingSuccessResponseData = {\n uuid: string;\n name: string;\n type: string;\n component: {\n uuid: string;\n name: string;\n description: string;\n componentType: string;\n libraryType: string;\n rootLibrary: boolean;\n references: {\n url: string;\n homePage: string;\n genericPackageIndex: string;\n };\n groupId: string;\n artifactId: string;\n version: string;\n path: string;\n };\n findingInfo: {\n status: string;\n comment: unknown;\n detectedAt: string;\n modifiedAt: string;\n };\n project: {\n uuid: string;\n name: string;\n path: string;\n applicationUuid: string;\n };\n application: {\n uuid: string;\n name: string;\n };\n vulnerability: {\n name: string;\n type: string;\n description: string;\n score: number;\n severity: StatisticsName;\n publishDate: string;\n modifiedDate: string;\n vulnerabilityScoring: {\n score: number;\n severity: string;\n type: string;\n }[];\n };\n topFix: {\n id: number;\n vulnerability: string;\n type: string;\n origin: string;\n url: string;\n fixResolution: string;\n date: string;\n message: string;\n };\n effective: string;\n threatAssessment: {\n exploitCodeMaturity: string;\n epssPercentage: number;\n };\n exploitable: boolean;\n scoreMetadataVector: string;\n};\n\nexport type GetDependenciesFindingSuccessResponseData = {\n supportToken: string;\n response: DependenciesFindingSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type GetDependenciesFindingsRequestData = {\n queryParams?: PaginationQueryParams;\n pathParams: PathParams;\n};\n\n// Containers Finding API Data\nexport type ContainersFindingSuccessResponseData = {\n uuid: string;\n vulnerabilityId: string;\n description: string;\n projectUuid: string;\n imageName: string;\n packageName: string;\n packageVersion: string;\n severity: StatisticsName;\n cvss: number;\n epss: number;\n hasFix: false;\n fixVersion: string;\n publishedDate: string;\n detectionDate: string;\n};\n\nexport type GetContainersFindingSuccessResponseData = {\n supportToken: string;\n response: ContainersFindingSuccessResponseData[];\n} & PaginationSuccessResponseData;\n\nexport type GetContainersFindingsRequestData = {\n queryParams?: PaginationQueryParams;\n pathParams: PathParams;\n};\n\nexport type Finding = {\n kind: StatisticsEngine;\n level: StatisticsName;\n name: string;\n origin: string;\n time: string;\n projectId: string;\n projectName: string;\n issue: {\n issueStatus: string;\n reporter: string;\n creationDate: string;\n ticketName: string;\n link: string;\n status: string;\n };\n};\n"],"names":["StatisticsEngine"],"mappings":";;AAoLO,IAAK,gBAAA,qBAAAA,iBAAAA,KAAL;AACL,EAAAA,kBAAA,cAAA,CAAA,GAAe,cAAA;AACf,EAAAA,kBAAA,MAAA,CAAA,GAAO,MAAA;AACP,EAAAA,kBAAA,YAAA,CAAA,GAAa,YAAA;AAHH,EAAA,OAAAA,iBAAAA;AAAA,CAAA,EAAA,gBAAA,IAAA,EAAA;;;;"}
@@ -4,13 +4,9 @@ var express = require('express');
4
4
  var Router = require('express-promise-router');
5
5
  var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
6
6
  var catalogClient = require('@backstage/catalog-client');
7
- var pluginPermissionCommon = require('@backstage/plugin-permission-common');
8
7
  var data_service_helpers = require('./data.service.helpers.cjs.js');
9
8
  var data_service = require('./data.service.cjs.js');
10
9
  var auth_service = require('./auth.service.cjs.js');
11
- var permissions = require('../permission/permissions.cjs.js');
12
- var conditions = require('../permission/conditions.cjs.js');
13
- require('../permission/rules.cjs.js');
14
10
  var constants = require('../constants.cjs.js');
15
11
 
16
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -19,11 +15,17 @@ var express__default = /*#__PURE__*/_interopDefaultCompat(express);
19
15
  var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
20
16
 
21
17
  async function createRouter(options) {
22
- const { logger, config, discovery, auth, httpAuth, permissions: permissions$1 } = options;
18
+ const { logger, config, discovery, auth, httpAuth } = options;
23
19
  const router = Router__default.default();
24
20
  router.use(express__default.default.json());
25
- router.use(conditions.permissionIntegrationRouter);
26
21
  const checkForAuth = (_request, response, next) => {
22
+ if (!auth_service.MendAuthSevice.isConfigured()) {
23
+ response.status(401).json({
24
+ name: "ConfigurationError",
25
+ message: auth_service.MendAuthSevice.getConfigurationError()
26
+ });
27
+ return;
28
+ }
27
29
  if (auth_service.MendAuthSevice.getAuthToken()) {
28
30
  next();
29
31
  return;
@@ -34,12 +36,35 @@ async function createRouter(options) {
34
36
  response.status(err?.status || 401).json({ error: err?.statusText || "Oops! Unauthorized" });
35
37
  });
36
38
  };
37
- const activationKey = config.getString("mend.activationKey");
39
+ const activationKey = config.getOptionalString("mend.activationKey") ?? "";
40
+ auth_service.MendAuthSevice.init({
41
+ apiVersion: constants.MEND_API_VERSION,
42
+ activationKey,
43
+ logger
44
+ });
38
45
  const mendDataService = new data_service.MendDataService({
39
46
  apiVersion: constants.MEND_API_VERSION,
40
- activationKey
47
+ activationKey,
48
+ logger
41
49
  });
42
50
  const catalogClient$1 = new catalogClient.CatalogClient({ discoveryApi: discovery });
51
+ const filterProjectsByPermissionControl = (projectItems) => {
52
+ const permissionControl = config.getOptionalConfig(
53
+ "mend.permissionControl"
54
+ );
55
+ if (!permissionControl) {
56
+ return projectItems;
57
+ }
58
+ const ids = permissionControl.getOptionalStringArray("ids") || [];
59
+ const exclude = permissionControl.getOptionalBoolean("exclude") ?? true;
60
+ if (ids.length === 0) {
61
+ return projectItems;
62
+ }
63
+ return projectItems.filter((item) => {
64
+ const isInList = ids.includes(item.uuid);
65
+ return exclude ? !isInList : isInList;
66
+ });
67
+ };
43
68
  router.get("/project" /* PROJECT */, checkForAuth, async (request, response) => {
44
69
  try {
45
70
  const credentials = await httpAuth.credentials(request);
@@ -59,20 +84,8 @@ async function createRouter(options) {
59
84
  mendDataService.getOrganizationProject
60
85
  )
61
86
  ]);
62
- const decision = (await permissions$1.authorizeConditional(
63
- [{ permission: permissions.mendReadPermission }],
64
- {
65
- credentials
66
- }
67
- ))[0];
68
- let items;
69
- if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
70
- const filter = conditions.transformConditions(decision.conditions);
71
- items = results[1].filter(
72
- (item) => filter?.exclude ? !filter.ids.includes(item.uuid) : filter.ids.includes(item.uuid)
73
- );
74
- }
75
- const data = data_service_helpers.dataMatcher(results[0].items, items || results[1]);
87
+ const filteredItems = filterProjectsByPermissionControl(results[1]);
88
+ const data = data_service_helpers.dataMatcher(results[0].items, filteredItems);
76
89
  const projects = data_service_helpers.dataProjectParser(data, results[2]);
77
90
  response.json({
78
91
  ...projects,
@@ -93,7 +106,11 @@ async function createRouter(options) {
93
106
  });
94
107
  const uid = request.body.uid;
95
108
  if (!uid) {
96
- response.status(401).json({ error: "Oops! No UUID provided" });
109
+ response.status(400).json({
110
+ message: "Oops! No UUID provided",
111
+ clientUrl: auth_service.MendAuthSevice.getClientUrl(),
112
+ clientName: auth_service.MendAuthSevice.getClientName()
113
+ });
97
114
  return;
98
115
  }
99
116
  const projectResult = await Promise.all([
@@ -108,32 +125,15 @@ async function createRouter(options) {
108
125
  mendDataService.getOrganizationProject
109
126
  )
110
127
  ]);
111
- const decision = (await permissions$1.authorizeConditional(
112
- [{ permission: permissions.mendReadPermission }],
113
- {
114
- credentials
115
- }
116
- ))[0];
117
- let items;
118
- if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
119
- const filter = conditions.transformConditions(decision.conditions);
120
- items = projectResult[1].filter(
121
- (item) => filter?.exclude ? !filter.ids.includes(item.uuid) : filter.ids.includes(item.uuid)
122
- );
123
- }
124
- const data = data_service_helpers.dataMatcher(
125
- projectResult[0].items,
126
- items || projectResult[1]
127
- );
128
+ const filteredItems = filterProjectsByPermissionControl(projectResult[1]);
129
+ const data = data_service_helpers.dataMatcher(projectResult[0].items, filteredItems);
128
130
  const entityURL = data_service_helpers.parseEntityURL(
129
131
  projectResult[0].items[0]?.metadata?.annotations?.["backstage.io/source-location"]
130
132
  );
131
133
  const projectSourceUrl = entityURL?.host ? `${entityURL.host}${entityURL.path}` : "";
132
134
  if (!data.length) {
133
- response.json({
134
- findingList: [],
135
- projectList: [],
136
- projectSourceUrl,
135
+ response.status(404).json({
136
+ message: "Results for this repository are either unavailable on Mend or can not be accessed.",
137
137
  clientUrl: auth_service.MendAuthSevice.getClientUrl(),
138
138
  clientName: auth_service.MendAuthSevice.getClientName()
139
139
  });
@@ -1 +1 @@
1
- {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["import express from 'express';\nimport Router from 'express-promise-router';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport {\n LoggerService,\n DiscoveryService,\n AuthService,\n HttpAuthService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Config } from '@backstage/config';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport {\n dataFindingParser,\n dataMatcher,\n dataProjectParser,\n fetchQueryPagination,\n parseEntityURL,\n} from './data.service.helpers';\nimport { MendDataService } from './data.service';\nimport { MendAuthSevice } from './auth.service';\nimport {\n PaginationQueryParams,\n ProjectStatisticsSuccessResponseData,\n OrganizationProjectSuccessResponseData,\n CodeFindingSuccessResponseData,\n DependenciesFindingSuccessResponseData,\n ContainersFindingSuccessResponseData,\n Finding,\n} from './data.service.types';\nimport {\n mendReadPermission,\n transformConditions,\n permissionIntegrationRouter,\n type FilterProps,\n} from '../permission';\nimport { MEND_API_VERSION } from '../constants';\n\n/** @internal */\nexport type RouterOptions = {\n logger: LoggerService;\n config: Config;\n discovery: DiscoveryService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n permissions: PermissionsService;\n};\n\nenum ROUTE {\n PROJECT = '/project',\n FINDING = '/finding',\n}\n\n/** @internal */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, discovery, auth, httpAuth, permissions } = options;\n\n const router = Router();\n router.use(express.json());\n\n router.use(permissionIntegrationRouter);\n\n const checkForAuth = (\n _request: express.Request,\n response: express.Response,\n next: express.NextFunction,\n ) => {\n if (MendAuthSevice.getAuthToken()) {\n next();\n return;\n }\n\n MendAuthSevice.connect()\n .then(next)\n .catch(err => {\n const errorMessage =\n err instanceof Error ? err?.message : err?.statusText;\n logger.error(errorMessage || 'Oops! Unauthorized');\n response\n .status(err?.status || 401)\n .json({ error: err?.statusText || 'Oops! Unauthorized' });\n });\n };\n\n const activationKey = config.getString('mend.activationKey');\n\n // Init api service\n const mendDataService = new MendDataService({\n apiVersion: MEND_API_VERSION,\n activationKey,\n });\n\n // Init catalog client\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n // Routes\n router.get(ROUTE.PROJECT, checkForAuth, async (request, response) => {\n try {\n // service to service auth\n const credentials = await httpAuth.credentials(request);\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n // entity to project match\n const results = await Promise.all([\n catalogClient.getEntities(\n { filter: [{ kind: ['Component'] }] },\n { token },\n ),\n fetchQueryPagination<ProjectStatisticsSuccessResponseData>(\n mendDataService.getProjectStatistics,\n ),\n fetchQueryPagination<OrganizationProjectSuccessResponseData>(\n mendDataService.getOrganizationProject,\n ),\n ]);\n\n // permission - filter to exclude or include project\n const decision = (\n await permissions.authorizeConditional(\n [{ permission: mendReadPermission }],\n {\n credentials,\n },\n )\n )[0];\n\n let items;\n if (decision.result === AuthorizeResult.CONDITIONAL) {\n const filter = transformConditions(decision.conditions) as FilterProps;\n items = results[1].filter(item =>\n filter?.exclude\n ? !filter.ids.includes(item.uuid)\n : filter.ids.includes(item.uuid),\n );\n }\n\n const data = dataMatcher(results[0].items, items || results[1]);\n\n // parse data\n const projects = dataProjectParser(data, results[2]);\n\n response.json({\n ...projects,\n clientUrl: MendAuthSevice.getClientUrl(),\n clientName: MendAuthSevice.getClientName(),\n });\n // Allow any object structure here\n } catch (error: any) {\n logger.error('/project', error);\n response.status(500).json({ error: 'Oops! Please try again later.' });\n }\n });\n\n router.post(ROUTE.FINDING, checkForAuth, async (request, response) => {\n try {\n // service to service auth\n const credentials = await httpAuth.credentials(request);\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n // entity to project match\n const uid = request.body.uid;\n\n if (!uid) {\n response.status(401).json({ error: 'Oops! No UUID provided' });\n return;\n }\n\n const projectResult = await Promise.all([\n catalogClient.getEntities(\n { filter: [{ 'metadata.uid': uid }] },\n { token },\n ),\n fetchQueryPagination<ProjectStatisticsSuccessResponseData>(\n mendDataService.getProjectStatistics,\n ),\n fetchQueryPagination<OrganizationProjectSuccessResponseData>(\n mendDataService.getOrganizationProject,\n ),\n ]);\n\n // permission - filter to exclude or include project\n const decision = (\n await permissions.authorizeConditional(\n [{ permission: mendReadPermission }],\n {\n credentials,\n },\n )\n )[0];\n\n let items;\n if (decision.result === AuthorizeResult.CONDITIONAL) {\n const filter = transformConditions(decision.conditions) as FilterProps;\n items = projectResult[1].filter(item =>\n filter?.exclude\n ? !filter.ids.includes(item.uuid)\n : filter.ids.includes(item.uuid),\n );\n }\n\n const data = dataMatcher(\n projectResult[0].items,\n items || projectResult[1],\n );\n\n const entityURL = parseEntityURL(\n projectResult[0].items[0]?.metadata?.annotations?.[\n 'backstage.io/source-location'\n ],\n );\n\n const projectSourceUrl = entityURL?.host\n ? `${entityURL.host}${entityURL.path}`\n : '';\n\n if (!data.length) {\n response.json({\n findingList: [],\n projectList: [],\n projectSourceUrl,\n clientUrl: MendAuthSevice.getClientUrl(),\n clientName: MendAuthSevice.getClientName(),\n });\n return;\n }\n\n const findingList: Finding[] = [];\n\n for (const projectItem of data) {\n const params = {\n pathParams: {\n uuid: projectItem.uuid,\n },\n };\n\n // get project findings\n const findingResult = await Promise.all([\n fetchQueryPagination<CodeFindingSuccessResponseData>(\n (queryParam: PaginationQueryParams) =>\n mendDataService.getCodeFinding({\n ...params,\n ...queryParam,\n }),\n ),\n fetchQueryPagination<DependenciesFindingSuccessResponseData>(\n (queryParam: PaginationQueryParams) =>\n mendDataService.getDependenciesFinding({\n ...params,\n ...queryParam,\n }),\n ),\n fetchQueryPagination<ContainersFindingSuccessResponseData>(\n (queryParam: PaginationQueryParams) =>\n mendDataService.getContainersFinding({\n ...params,\n ...queryParam,\n }),\n ),\n ]);\n\n const tempFindingList: Finding[] = dataFindingParser(\n findingResult[0].filter(item => !item.suppressed), // NOTE: Do not show suppressed item\n findingResult[1].filter(\n item => !(item.findingInfo.status === 'IGNORED'),\n projectItem,\n ), // NOTE: Do not show ignored item\n findingResult[2], // ESC-51: Follow Jira activity\n projectItem.name,\n );\n findingList.push(...tempFindingList);\n }\n\n const projects = dataProjectParser(data, projectResult[2]);\n\n response.json({\n findingList,\n ...projects,\n projectSourceUrl,\n clientUrl: MendAuthSevice.getClientUrl(),\n clientName: MendAuthSevice.getClientName(),\n });\n // Allow any object structure here\n } catch (error: any) {\n logger.error('/finding', error);\n response.status(500).json({ error: 'Oops! Please try again later.' });\n }\n });\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n\n router.use(middleware.error());\n return router;\n}\n"],"names":["permissions","Router","express","permissionIntegrationRouter","MendAuthSevice","MendDataService","MEND_API_VERSION","catalogClient","CatalogClient","fetchQueryPagination","mendReadPermission","AuthorizeResult","transformConditions","dataMatcher","dataProjectParser","parseEntityURL","dataFindingParser","MiddlewareFactory"],"mappings":"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"}
1
+ {"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport {\n LoggerService,\n DiscoveryService,\n AuthService,\n HttpAuthService,\n} from '@backstage/backend-plugin-api';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport type { Config } from '@backstage/config';\nimport {\n dataFindingParser,\n dataMatcher,\n dataProjectParser,\n fetchQueryPagination,\n parseEntityURL,\n} from './data.service.helpers';\nimport { MendDataService } from './data.service';\nimport { MendAuthSevice } from './auth.service';\nimport {\n PaginationQueryParams,\n ProjectStatisticsSuccessResponseData,\n OrganizationProjectSuccessResponseData,\n CodeFindingSuccessResponseData,\n DependenciesFindingSuccessResponseData,\n ContainersFindingSuccessResponseData,\n Finding,\n} from './data.service.types';\nimport { MEND_API_VERSION } from '../constants';\n\n/** @internal */\nexport type RouterOptions = {\n logger: LoggerService;\n config: Config;\n discovery: DiscoveryService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n};\n\nenum ROUTE {\n PROJECT = '/project',\n FINDING = '/finding',\n}\n\n/** @internal */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, discovery, auth, httpAuth } = options;\n\n const router = Router();\n router.use(express.json());\n\n const checkForAuth = (\n _request: express.Request,\n response: express.Response,\n next: express.NextFunction,\n ) => {\n // Check if activation key is configured\n if (!MendAuthSevice.isConfigured()) {\n response.status(401).json({\n name: 'ConfigurationError',\n message: MendAuthSevice.getConfigurationError(),\n });\n return;\n }\n\n if (MendAuthSevice.getAuthToken()) {\n next();\n return;\n }\n\n MendAuthSevice.connect()\n .then(next)\n .catch(err => {\n const errorMessage =\n err instanceof Error ? err?.message : err?.statusText;\n logger.error(errorMessage || 'Oops! Unauthorized');\n response\n .status(err?.status || 401)\n .json({ error: err?.statusText || 'Oops! Unauthorized' });\n });\n };\n\n const activationKey = config.getOptionalString('mend.activationKey') ?? '';\n\n // Init auth service with logger (logs warning if activation key is missing/invalid)\n MendAuthSevice.init({\n apiVersion: MEND_API_VERSION,\n activationKey,\n logger,\n });\n\n // Init api service\n const mendDataService = new MendDataService({\n apiVersion: MEND_API_VERSION,\n activationKey,\n logger,\n });\n\n // Init catalog client\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n /**\n * Filters project IDs based on mend.permissionControl configuration\n * @param projectItems - Array of project items to filter\n * @returns Filtered array of project items\n */\n const filterProjectsByPermissionControl = <T extends { uuid: string }>(\n projectItems: T[],\n ): T[] => {\n const permissionControl = config.getOptionalConfig(\n 'mend.permissionControl',\n );\n\n if (!permissionControl) {\n // No permission control configured, return all items\n return projectItems;\n }\n\n const ids = permissionControl.getOptionalStringArray('ids') || [];\n const exclude = permissionControl.getOptionalBoolean('exclude') ?? true;\n\n if (ids.length === 0) {\n // No IDs configured, return all items\n return projectItems;\n }\n\n return projectItems.filter(item => {\n const isInList = ids.includes(item.uuid);\n // If exclude is true (blocklist mode): filter out items in the list\n // If exclude is false (allowlist mode): only include items in the list\n return exclude ? !isInList : isInList;\n });\n };\n\n // Routes\n router.get(ROUTE.PROJECT, checkForAuth, async (request, response) => {\n try {\n // service to service auth\n const credentials = await httpAuth.credentials(request);\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n // entity to project match\n const results = await Promise.all([\n catalogClient.getEntities(\n { filter: [{ kind: ['Component'] }] },\n { token },\n ),\n fetchQueryPagination<ProjectStatisticsSuccessResponseData>(\n mendDataService.getProjectStatistics,\n ),\n fetchQueryPagination<OrganizationProjectSuccessResponseData>(\n mendDataService.getOrganizationProject,\n ),\n ]);\n\n // Apply permission control from config\n const filteredItems = filterProjectsByPermissionControl(results[1]);\n\n const data = dataMatcher(results[0].items, filteredItems);\n\n // parse data\n const projects = dataProjectParser(data, results[2]);\n\n response.json({\n ...projects,\n clientUrl: MendAuthSevice.getClientUrl(),\n clientName: MendAuthSevice.getClientName(),\n });\n // Allow any object structure here\n } catch (error: any) {\n logger.error('/project', error);\n response.status(500).json({ error: 'Oops! Please try again later.' });\n }\n });\n\n router.post(ROUTE.FINDING, checkForAuth, async (request, response) => {\n try {\n // service to service auth\n const credentials = await httpAuth.credentials(request);\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n // entity to project match\n const uid = request.body.uid;\n\n if (!uid) {\n response.status(400).json({\n message: 'Oops! No UUID provided',\n clientUrl: MendAuthSevice.getClientUrl(),\n clientName: MendAuthSevice.getClientName(),\n });\n return;\n }\n\n const projectResult = await Promise.all([\n catalogClient.getEntities(\n { filter: [{ 'metadata.uid': uid }] },\n { token },\n ),\n fetchQueryPagination<ProjectStatisticsSuccessResponseData>(\n mendDataService.getProjectStatistics,\n ),\n fetchQueryPagination<OrganizationProjectSuccessResponseData>(\n mendDataService.getOrganizationProject,\n ),\n ]);\n\n // Apply permission control from config\n const filteredItems = filterProjectsByPermissionControl(projectResult[1]);\n\n const data = dataMatcher(projectResult[0].items, filteredItems);\n\n const entityURL = parseEntityURL(\n projectResult[0].items[0]?.metadata?.annotations?.[\n 'backstage.io/source-location'\n ],\n );\n\n const projectSourceUrl = entityURL?.host\n ? `${entityURL.host}${entityURL.path}`\n : '';\n\n if (!data.length) {\n response.status(404).json({\n message:\n 'Results for this repository are either unavailable on Mend or can not be accessed.',\n clientUrl: MendAuthSevice.getClientUrl(),\n clientName: MendAuthSevice.getClientName(),\n });\n return;\n }\n\n const findingList: Finding[] = [];\n\n for (const projectItem of data) {\n const params = {\n pathParams: {\n uuid: projectItem.uuid,\n },\n };\n\n // get project findings\n const findingResult = await Promise.all([\n fetchQueryPagination<CodeFindingSuccessResponseData>(\n (queryParam: PaginationQueryParams) =>\n mendDataService.getCodeFinding({\n ...params,\n ...queryParam,\n }),\n ),\n fetchQueryPagination<DependenciesFindingSuccessResponseData>(\n (queryParam: PaginationQueryParams) =>\n mendDataService.getDependenciesFinding({\n ...params,\n ...queryParam,\n }),\n ),\n fetchQueryPagination<ContainersFindingSuccessResponseData>(\n (queryParam: PaginationQueryParams) =>\n mendDataService.getContainersFinding({\n ...params,\n ...queryParam,\n }),\n ),\n ]);\n\n const tempFindingList: Finding[] = dataFindingParser(\n findingResult[0].filter(item => !item.suppressed), // NOTE: Do not show suppressed item\n findingResult[1].filter(\n item => !(item.findingInfo.status === 'IGNORED'),\n projectItem,\n ), // NOTE: Do not show ignored item\n findingResult[2], // ESC-51: Follow Jira activity\n projectItem.name,\n );\n findingList.push(...tempFindingList);\n }\n\n const projects = dataProjectParser(data, projectResult[2]);\n\n response.json({\n findingList,\n ...projects,\n projectSourceUrl,\n clientUrl: MendAuthSevice.getClientUrl(),\n clientName: MendAuthSevice.getClientName(),\n });\n // Allow any object structure here\n } catch (error: any) {\n logger.error('/finding', error);\n response.status(500).json({ error: 'Oops! Please try again later.' });\n }\n });\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n\n router.use(middleware.error());\n return router;\n}\n"],"names":["Router","express","MendAuthSevice","MEND_API_VERSION","MendDataService","catalogClient","CatalogClient","fetchQueryPagination","dataMatcher","dataProjectParser","parseEntityURL","dataFindingParser","MiddlewareFactory"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage-community/plugin-mend-backend",
3
- "version": "0.10.0",
3
+ "version": "1.1.0",
4
4
  "main": "dist/index.cjs.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -37,14 +37,14 @@
37
37
  "postpack": "backstage-cli package postpack"
38
38
  },
39
39
  "dependencies": {
40
- "@backstage/backend-defaults": "^0.14.0",
41
- "@backstage/backend-plugin-api": "^1.6.0",
42
- "@backstage/catalog-client": "^1.12.1",
40
+ "@backstage/backend-defaults": "^0.15.2",
41
+ "@backstage/backend-plugin-api": "^1.7.0",
42
+ "@backstage/catalog-client": "^1.13.0",
43
43
  "@backstage/catalog-model": "^1.7.6",
44
44
  "@backstage/config": "^1.3.6",
45
- "@backstage/plugin-permission-common": "^0.9.3",
46
- "@backstage/plugin-permission-node": "^0.10.7",
47
- "@types/express": "*",
45
+ "@backstage/plugin-permission-common": "^0.9.6",
46
+ "@backstage/plugin-permission-node": "^0.10.10",
47
+ "@types/express": "^4.17.6",
48
48
  "express": "^4.17.1",
49
49
  "express-promise-router": "^4.1.0",
50
50
  "jsonwebtoken": "^9.0.2",
@@ -55,11 +55,12 @@
55
55
  "zod": "^3.23.8"
56
56
  },
57
57
  "devDependencies": {
58
- "@backstage/backend-test-utils": "^1.10.2",
59
- "@backstage/cli": "^0.35.1",
60
- "@backstage/plugin-auth-backend": "^0.25.7",
61
- "@backstage/plugin-auth-backend-module-guest-provider": "^0.2.15",
62
- "@types/supertest": "^2.0.12",
58
+ "@backstage/backend-test-utils": "^1.11.0",
59
+ "@backstage/cli": "^0.35.4",
60
+ "@backstage/plugin-auth-backend": "^0.27.0",
61
+ "@backstage/plugin-auth-backend-module-guest-provider": "^0.2.16",
62
+ "@backstage/plugin-catalog-backend": "^3.4.0",
63
+ "@types/supertest": "^6.0.0",
63
64
  "msw": "^1.0.0",
64
65
  "supertest": "^7.0.0"
65
66
  },
@@ -1,33 +0,0 @@
1
- 'use strict';
2
-
3
- var pluginPermissionNode = require('@backstage/plugin-permission-node');
4
- var rules = require('./rules.cjs.js');
5
- var permissions = require('./permissions.cjs.js');
6
-
7
- const { conditions, createConditionalDecision } = pluginPermissionNode.createConditionExports({
8
- pluginId: "mend",
9
- resourceType: permissions.RESOURCE_TYPE.PROJECT,
10
- rules: rules.rules
11
- });
12
- const mendConditions = conditions;
13
- const createMendProjectConditionalDecision = createConditionalDecision;
14
- const permissionIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
15
- permissions: [permissions.mendReadPermission],
16
- getResources: async (resourceRefs) => {
17
- return resourceRefs.map((resourceRef) => {
18
- return {
19
- permission: permissions.mendReadPermission,
20
- resourceRef
21
- };
22
- });
23
- },
24
- resourceType: permissions.RESOURCE_TYPE.PROJECT,
25
- rules: Object.values(rules.rules)
26
- });
27
- const transformConditions = pluginPermissionNode.createConditionTransformer(Object.values(rules.rules));
28
-
29
- exports.createMendProjectConditionalDecision = createMendProjectConditionalDecision;
30
- exports.mendConditions = mendConditions;
31
- exports.permissionIntegrationRouter = permissionIntegrationRouter;
32
- exports.transformConditions = transformConditions;
33
- //# sourceMappingURL=conditions.cjs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"conditions.cjs.js","sources":["../../src/permission/conditions.ts"],"sourcesContent":["import express from 'express';\nimport { createConditionExports } from '@backstage/plugin-permission-node';\nimport {\n createPermissionIntegrationRouter,\n createConditionTransformer,\n ConditionTransformer,\n} from '@backstage/plugin-permission-node';\nimport { rules, type FilterProps } from './rules';\nimport { RESOURCE_TYPE, mendReadPermission } from './permissions';\n\nconst { conditions, createConditionalDecision } = createConditionExports({\n pluginId: 'mend',\n resourceType: RESOURCE_TYPE.PROJECT,\n rules,\n});\n\n/** @public */\nexport const mendConditions = conditions;\n\n/** @public */\nexport const createMendProjectConditionalDecision = createConditionalDecision;\n\nexport const permissionIntegrationRouter: express.Router =\n createPermissionIntegrationRouter({\n permissions: [mendReadPermission],\n getResources: async resourceRefs => {\n return resourceRefs.map(resourceRef => {\n return {\n permission: mendReadPermission,\n resourceRef,\n };\n });\n },\n resourceType: RESOURCE_TYPE.PROJECT,\n rules: Object.values(rules),\n });\n\nexport const transformConditions: ConditionTransformer<FilterProps> =\n createConditionTransformer(Object.values(rules));\n"],"names":["createConditionExports","RESOURCE_TYPE","rules","createPermissionIntegrationRouter","mendReadPermission","createConditionTransformer"],"mappings":";;;;;;AAUA,MAAM,EAAE,UAAA,EAAY,yBAA0B,EAAA,GAAIA,2CAAuB,CAAA;AAAA,EACvE,QAAU,EAAA,MAAA;AAAA,EACV,cAAcC,yBAAc,CAAA,OAAA;AAAA,SAC5BC;AACF,CAAC,CAAA;AAGM,MAAM,cAAiB,GAAA;AAGvB,MAAM,oCAAuC,GAAA;AAE7C,MAAM,8BACXC,sDAAkC,CAAA;AAAA,EAChC,WAAA,EAAa,CAACC,8BAAkB,CAAA;AAAA,EAChC,YAAA,EAAc,OAAM,YAAgB,KAAA;AAClC,IAAO,OAAA,YAAA,CAAa,IAAI,CAAe,WAAA,KAAA;AACrC,MAAO,OAAA;AAAA,QACL,UAAY,EAAAA,8BAAA;AAAA,QACZ;AAAA,OACF;AAAA,KACD,CAAA;AAAA,GACH;AAAA,EACA,cAAcH,yBAAc,CAAA,OAAA;AAAA,EAC5B,KAAA,EAAO,MAAO,CAAA,MAAA,CAAOC,WAAK;AAC5B,CAAC;AAEI,MAAM,mBACX,GAAAG,+CAAA,CAA2B,MAAO,CAAA,MAAA,CAAOH,WAAK,CAAC;;;;;;;"}
@@ -1,17 +0,0 @@
1
- 'use strict';
2
-
3
- var pluginPermissionCommon = require('@backstage/plugin-permission-common');
4
-
5
- var RESOURCE_TYPE = /* @__PURE__ */ ((RESOURCE_TYPE2) => {
6
- RESOURCE_TYPE2["PROJECT"] = "mend-project";
7
- return RESOURCE_TYPE2;
8
- })(RESOURCE_TYPE || {});
9
- const mendReadPermission = pluginPermissionCommon.createPermission({
10
- name: "mend.project.read",
11
- attributes: { action: "read" },
12
- resourceType: "mend-project" /* PROJECT */
13
- });
14
-
15
- exports.RESOURCE_TYPE = RESOURCE_TYPE;
16
- exports.mendReadPermission = mendReadPermission;
17
- //# sourceMappingURL=permissions.cjs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"permissions.cjs.js","sources":["../../src/permission/permissions.ts"],"sourcesContent":["import { createPermission } from '@backstage/plugin-permission-common';\n\n/** @public */\nexport enum RESOURCE_TYPE {\n PROJECT = 'mend-project',\n}\n\n/** @public */\nexport const mendReadPermission = createPermission({\n name: 'mend.project.read',\n attributes: { action: 'read' },\n resourceType: RESOURCE_TYPE.PROJECT,\n});\n\nexport const mendPermissions = [mendReadPermission];\n"],"names":["RESOURCE_TYPE","createPermission"],"mappings":";;;;AAGY,IAAA,aAAA,qBAAAA,cAAL,KAAA;AACL,EAAAA,eAAA,SAAU,CAAA,GAAA,cAAA;AADA,EAAAA,OAAAA,cAAAA;AAAA,CAAA,EAAA,aAAA,IAAA,EAAA;AAKL,MAAM,qBAAqBC,uCAAiB,CAAA;AAAA,EACjD,IAAM,EAAA,mBAAA;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAO,EAAA;AAAA,EAC7B,YAAc,EAAA,cAAA;AAChB,CAAC;;;;;"}
@@ -1,31 +0,0 @@
1
- 'use strict';
2
-
3
- var zod = require('zod');
4
- var pluginPermissionNode = require('@backstage/plugin-permission-node');
5
- var permissions = require('./permissions.cjs.js');
6
-
7
- const createProjectPermissionRule = pluginPermissionNode.makeCreatePermissionRule();
8
- const filter = createProjectPermissionRule({
9
- name: "filter",
10
- description: "Should allow read-only access to filtered projects.",
11
- resourceType: permissions.RESOURCE_TYPE.PROJECT,
12
- paramsSchema: zod.z.object({
13
- ids: zod.z.string().array().describe("Project ID to match resource"),
14
- exclude: zod.z.boolean().optional().describe("Exclude or include project")
15
- }),
16
- apply: (resource, { ids, exclude = true }) => {
17
- return exclude ? !ids.includes(resource.resourceRef) : ids.includes(resource.resourceRef);
18
- },
19
- toQuery: ({ ids, exclude = true }) => {
20
- return {
21
- ids,
22
- exclude
23
- };
24
- }
25
- });
26
- const rules = { filter };
27
-
28
- exports.createProjectPermissionRule = createProjectPermissionRule;
29
- exports.filter = filter;
30
- exports.rules = rules;
31
- //# sourceMappingURL=rules.cjs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rules.cjs.js","sources":["../../src/permission/rules.ts"],"sourcesContent":["import { z } from 'zod';\nimport { makeCreatePermissionRule } from '@backstage/plugin-permission-node';\nimport { RESOURCE_TYPE } from './permissions';\n\ntype PermissionAttributes = {\n action?: 'create' | 'read' | 'update' | 'delete';\n};\n\ntype ResourceProps = {\n permission: {\n type: string;\n name: string;\n attributes: PermissionAttributes;\n resourceType: typeof RESOURCE_TYPE.PROJECT;\n };\n resourceRef: string;\n};\n\n/** @public */\nexport type FilterProps = {\n ids: string[];\n exclude?: boolean;\n};\n\nexport const createProjectPermissionRule = makeCreatePermissionRule<\n ResourceProps,\n FilterProps,\n typeof RESOURCE_TYPE.PROJECT\n>();\n\nexport const filter = createProjectPermissionRule({\n name: 'filter',\n description: 'Should allow read-only access to filtered projects.',\n resourceType: RESOURCE_TYPE.PROJECT,\n paramsSchema: z.object({\n ids: z.string().array().describe('Project ID to match resource'),\n exclude: z.boolean().optional().describe('Exclude or include project'),\n }),\n apply: (resource, { ids, exclude = true }) => {\n return exclude\n ? !ids.includes(resource.resourceRef)\n : ids.includes(resource.resourceRef);\n },\n toQuery: ({ ids, exclude = true }) => {\n return {\n ids,\n exclude,\n };\n },\n});\n\nexport const rules = { filter };\n"],"names":["makeCreatePermissionRule","RESOURCE_TYPE","z"],"mappings":";;;;;;AAwBO,MAAM,8BAA8BA,6CAIzC;AAEK,MAAM,SAAS,2BAA4B,CAAA;AAAA,EAChD,IAAM,EAAA,QAAA;AAAA,EACN,WAAa,EAAA,qDAAA;AAAA,EACb,cAAcC,yBAAc,CAAA,OAAA;AAAA,EAC5B,YAAA,EAAcC,MAAE,MAAO,CAAA;AAAA,IACrB,KAAKA,KAAE,CAAA,MAAA,GAAS,KAAM,EAAA,CAAE,SAAS,8BAA8B,CAAA;AAAA,IAC/D,SAASA,KAAE,CAAA,OAAA,GAAU,QAAS,EAAA,CAAE,SAAS,4BAA4B;AAAA,GACtE,CAAA;AAAA,EACD,OAAO,CAAC,QAAA,EAAU,EAAE,GAAK,EAAA,OAAA,GAAU,MAAW,KAAA;AAC5C,IAAO,OAAA,OAAA,GACH,CAAC,GAAA,CAAI,QAAS,CAAA,QAAA,CAAS,WAAW,CAClC,GAAA,GAAA,CAAI,QAAS,CAAA,QAAA,CAAS,WAAW,CAAA;AAAA,GACvC;AAAA,EACA,SAAS,CAAC,EAAE,GAAK,EAAA,OAAA,GAAU,MAAW,KAAA;AACpC,IAAO,OAAA;AAAA,MACL,GAAA;AAAA,MACA;AAAA,KACF;AAAA;AAEJ,CAAC;AAEY,MAAA,KAAA,GAAQ,EAAE,MAAO;;;;;;"}