@backstage-community/plugin-mend-backend 0.6.0 → 0.8.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 +17 -0
- package/README.md +3 -3
- package/config.d.ts +0 -4
- package/dist/api/index.cjs.js +1 -1
- package/dist/api/index.cjs.js.map +1 -1
- package/dist/constants.cjs.js +8 -0
- package/dist/constants.cjs.js.map +1 -0
- package/dist/service/auth.service.cjs.js +62 -15
- package/dist/service/auth.service.cjs.js.map +1 -1
- package/dist/service/data.service.helpers.cjs.js +13 -10
- package/dist/service/data.service.helpers.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +12 -4
- package/dist/service/router.cjs.js.map +1 -1
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @backstage-community/plugin-mend-backend
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 063ba67: Backstage version bump to v1.43.2
|
|
8
|
+
|
|
9
|
+
## 0.7.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- d85e394: Removed the `baseUrl` field from the Backstage configuration; now derived using the `activationKey`.
|
|
14
|
+
Enhanced drill-down functionality to filter projects on the Findings Overview page using the `sourceUrl`.
|
|
15
|
+
Added support for displaying projects with `sourceUrl` from GitLab, Bitbucket, and Azure Repos.
|
|
16
|
+
Updated branding text from `mend.io` to `Mend.io`.
|
|
17
|
+
Improved and repositioned the Project Name multi-select filter on the Findings Overview page.
|
|
18
|
+
Added tooltip for the Project Name multi-select filter.
|
|
19
|
+
|
|
3
20
|
## 0.6.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Mend.io - backend
|
|
2
2
|
|
|
3
3
|
> [!IMPORTANT]
|
|
4
4
|
> New Backend System
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
mendReadPermission,
|
|
25
25
|
mendConditions,
|
|
26
26
|
createMendProjectConditionalDecision,
|
|
27
|
-
} from '@
|
|
27
|
+
} from '@backstage-community/plugin-mend-backend';
|
|
28
28
|
// ... other polices
|
|
29
29
|
export class OrganizationPolicy implements PermissionPolicy {
|
|
30
30
|
async handle(
|
|
@@ -49,6 +49,6 @@ export class OrganizationPolicy implements PermissionPolicy {
|
|
|
49
49
|
// ...
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
**Add the
|
|
52
|
+
**Add the Mend.io frontend plugin**
|
|
53
53
|
|
|
54
54
|
See the [mend frontend plugin instructions](../mend/README.md).
|
package/config.d.ts
CHANGED
package/dist/api/index.cjs.js
CHANGED
|
@@ -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(
|
|
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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"}
|
|
@@ -0,0 +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;;;;;"}
|
|
@@ -18,15 +18,43 @@ class MendAuthSevice {
|
|
|
18
18
|
static clientName = "";
|
|
19
19
|
static clientUuid = "";
|
|
20
20
|
constructor(config) {
|
|
21
|
-
|
|
22
|
-
this.getConfig(config.activationKey);
|
|
21
|
+
this.getConfig(config.apiVersion, config.activationKey);
|
|
23
22
|
}
|
|
24
|
-
getConfig(activationKey) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
getConfig(apiVersion, activationKey) {
|
|
24
|
+
try {
|
|
25
|
+
const licenseKey = auth_service_helpers.caesarCipherDecrypt(activationKey);
|
|
26
|
+
const decoded = jwt__default.default.decode(licenseKey);
|
|
27
|
+
if (!decoded || typeof decoded !== "object") {
|
|
28
|
+
throw new Error(
|
|
29
|
+
"Invalid activation key: could not decode license payload"
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
const jwtPayload = decoded;
|
|
33
|
+
const { wsEnvUrl, integratorEmail, userKey } = jwtPayload || {};
|
|
34
|
+
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)"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
let baseUrl;
|
|
40
|
+
try {
|
|
41
|
+
baseUrl = new URL(wsEnvUrl);
|
|
42
|
+
} catch {
|
|
43
|
+
throw new Error("Invalid activation key: wsEnvUrl is not a valid URL");
|
|
44
|
+
}
|
|
45
|
+
baseUrl.hostname = `api-${baseUrl.hostname}`;
|
|
46
|
+
baseUrl.pathname = `/api/${apiVersion}`;
|
|
47
|
+
MendAuthSevice.baseUrl = baseUrl.toString();
|
|
48
|
+
MendAuthSevice.clientEmail = integratorEmail;
|
|
49
|
+
MendAuthSevice.clientKey = userKey;
|
|
50
|
+
MendAuthSevice.clientUrl = wsEnvUrl;
|
|
51
|
+
} catch (err) {
|
|
52
|
+
MendAuthSevice.baseUrl = "";
|
|
53
|
+
MendAuthSevice.clientEmail = "";
|
|
54
|
+
MendAuthSevice.clientKey = "";
|
|
55
|
+
MendAuthSevice.clientUrl = "";
|
|
56
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
57
|
+
}
|
|
30
58
|
}
|
|
31
59
|
static async login() {
|
|
32
60
|
return index.post("/login" /* LOGIN */, {
|
|
@@ -35,8 +63,14 @@ class MendAuthSevice {
|
|
|
35
63
|
userKey: this.clientKey
|
|
36
64
|
}
|
|
37
65
|
}).then((data) => {
|
|
66
|
+
if (!data?.response?.refreshToken) {
|
|
67
|
+
throw new Error("Login failed: missing refreshToken in response");
|
|
68
|
+
}
|
|
38
69
|
this.refreshToken = data.response.refreshToken;
|
|
39
70
|
return Promise.resolve();
|
|
71
|
+
}).catch((err) => {
|
|
72
|
+
this.refreshToken = "";
|
|
73
|
+
return Promise.reject(err);
|
|
40
74
|
});
|
|
41
75
|
}
|
|
42
76
|
static async refreshAccessToken() {
|
|
@@ -48,16 +82,24 @@ class MendAuthSevice {
|
|
|
48
82
|
}
|
|
49
83
|
}
|
|
50
84
|
).then((data) => {
|
|
85
|
+
if (!data?.response?.jwtToken) {
|
|
86
|
+
throw new Error("Refresh token failed: missing jwtToken in response");
|
|
87
|
+
}
|
|
51
88
|
this.authToken = data.response.jwtToken;
|
|
52
|
-
this.clientName = data.response.orgName;
|
|
53
|
-
this.clientUuid = data.response.orgUuid;
|
|
89
|
+
this.clientName = data.response.orgName ?? "";
|
|
90
|
+
this.clientUuid = data.response.orgUuid ?? "";
|
|
54
91
|
return Promise.resolve();
|
|
92
|
+
}).catch((err) => {
|
|
93
|
+
this.authToken = "";
|
|
94
|
+
this.clientName = "";
|
|
95
|
+
this.clientUuid = "";
|
|
96
|
+
return Promise.reject(err);
|
|
55
97
|
});
|
|
56
98
|
}
|
|
57
99
|
static async connect() {
|
|
58
|
-
return MendAuthSevice.login().then(
|
|
59
|
-
|
|
60
|
-
);
|
|
100
|
+
return MendAuthSevice.login().then(() => MendAuthSevice.refreshAccessToken()).catch((err) => {
|
|
101
|
+
return Promise.reject(err);
|
|
102
|
+
});
|
|
61
103
|
}
|
|
62
104
|
static async validateAuthToken(url) {
|
|
63
105
|
if (["/login" /* LOGIN */, "/login/accessToken" /* REFRESH_TOKEN */].includes(url)) {
|
|
@@ -66,8 +108,13 @@ class MendAuthSevice {
|
|
|
66
108
|
if (!this.authToken) {
|
|
67
109
|
return this.connect();
|
|
68
110
|
}
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
111
|
+
const decoded = jwt__default.default.decode(this.authToken);
|
|
112
|
+
if (!decoded || typeof decoded !== "object" || !("exp" in decoded)) {
|
|
113
|
+
return this.connect();
|
|
114
|
+
}
|
|
115
|
+
const token = decoded;
|
|
116
|
+
const expMs = Number(token.exp) * 1e3;
|
|
117
|
+
if (Number.isNaN(expMs) || expMs - Date.now() < 0) {
|
|
71
118
|
return this.connect();
|
|
72
119
|
}
|
|
73
120
|
return Promise.resolve();
|
|
@@ -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
|
|
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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"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var pathToRegexp = require('path-to-regexp');
|
|
4
4
|
var data_service_types = require('./data.service.types.cjs.js');
|
|
5
|
+
var constants = require('../constants.cjs.js');
|
|
5
6
|
|
|
6
7
|
const dataProjectParser = (projectStatistics, organizationProjects) => {
|
|
7
8
|
const organizationData = organizationProjects.reduce((prev, next) => {
|
|
@@ -66,9 +67,9 @@ const dataProjectParser = (projectStatistics, organizationProjects) => {
|
|
|
66
67
|
applicationName: organizationData[next.uuid].applicationName,
|
|
67
68
|
applicationUuid: next.applicationUuid,
|
|
68
69
|
lastScan: next.statistics["LAST_SCAN" /* LAST_SCAN */].lastScanTime,
|
|
69
|
-
languages: Object.entries(next.statistics.LIBRARY_TYPE_HISTOGRAM).sort(
|
|
70
|
+
languages: next.statistics?.LIBRARY_TYPE_HISTOGRAM ? Object.entries(next.statistics.LIBRARY_TYPE_HISTOGRAM).sort(
|
|
70
71
|
(a, b) => b[1] - a[1]
|
|
71
|
-
)
|
|
72
|
+
) : []
|
|
72
73
|
};
|
|
73
74
|
prev.projectList.unshift(project);
|
|
74
75
|
return prev;
|
|
@@ -94,10 +95,14 @@ const parseEntityURL = (entityUrl) => {
|
|
|
94
95
|
return null;
|
|
95
96
|
}
|
|
96
97
|
const url = new URL(matches[0]);
|
|
97
|
-
const
|
|
98
|
-
|
|
98
|
+
const hostname = url.host.toLowerCase();
|
|
99
|
+
let matcher = pathToRegexp.match("/:org/:repo", { end: false });
|
|
100
|
+
if (hostname === constants.AZURE_HOST_NAME) {
|
|
101
|
+
matcher = pathToRegexp.match("/:org/:project/_git/:repo", { end: false });
|
|
102
|
+
}
|
|
103
|
+
const extractedContent = matcher(url.pathname);
|
|
99
104
|
if (extractedContent) {
|
|
100
|
-
return { ...extractedContent, host:
|
|
105
|
+
return { ...extractedContent, host: hostname };
|
|
101
106
|
}
|
|
102
107
|
return null;
|
|
103
108
|
} catch (error) {
|
|
@@ -141,13 +146,10 @@ function getSourceURLWiseProject(projects) {
|
|
|
141
146
|
let sourceUrl = null;
|
|
142
147
|
if (sourceUrlTag && typeof sourceUrlTag.value === "string") {
|
|
143
148
|
sourceUrl = sourceUrlTag.value;
|
|
144
|
-
|
|
145
|
-
if (!/^https?:\/\//i.test(urlString)) {
|
|
146
|
-
urlString = `https://${urlString}`;
|
|
147
|
-
}
|
|
149
|
+
const urlString = sourceUrl.startsWith("http") ? sourceUrl : `https://${sourceUrl}`;
|
|
148
150
|
try {
|
|
149
151
|
const urlObj = new URL(urlString);
|
|
150
|
-
host = urlObj.host;
|
|
152
|
+
host = urlObj.host.toLocaleLowerCase();
|
|
151
153
|
pathname = urlObj.pathname;
|
|
152
154
|
} catch (e) {
|
|
153
155
|
}
|
|
@@ -291,4 +293,5 @@ exports.dataMatcher = dataMatcher;
|
|
|
291
293
|
exports.dataProjectParser = dataProjectParser;
|
|
292
294
|
exports.fetchQueryPagination = fetchQueryPagination;
|
|
293
295
|
exports.getSourceURLWiseProject = getSourceURLWiseProject;
|
|
296
|
+
exports.parseEntityURL = parseEntityURL;
|
|
294
297
|
//# sourceMappingURL=data.service.helpers.cjs.js.map
|
|
@@ -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';\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: Object.entries(next.statistics.LIBRARY_TYPE_HISTOGRAM).sort(\n (a, b) => b[1] - a[1],\n ),\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\nconst 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 fn = match('/:org/:repo', { end: false });\n const extractedContent = fn(url.pathname);\n if (extractedContent) {\n return { ...extractedContent, host: url.host };\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 let urlString = sourceUrl;\n // Prepend protocol if missing for URL parsing\n if (!/^https?:\\/\\//i.test(urlString)) {\n urlString = `https://${urlString}`;\n }\n try {\n const urlObj = new URL(urlString);\n host = urlObj.host;\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"],"mappings":"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"}
|
|
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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"}
|
|
@@ -11,6 +11,7 @@ var auth_service = require('./auth.service.cjs.js');
|
|
|
11
11
|
var permissions = require('../permission/permissions.cjs.js');
|
|
12
12
|
var conditions = require('../permission/conditions.cjs.js');
|
|
13
13
|
require('../permission/rules.cjs.js');
|
|
14
|
+
var constants = require('../constants.cjs.js');
|
|
14
15
|
|
|
15
16
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
16
17
|
|
|
@@ -27,14 +28,15 @@ async function createRouter(options) {
|
|
|
27
28
|
next();
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
30
|
-
auth_service.MendAuthSevice.connect().then(next).catch(() => {
|
|
31
|
-
|
|
31
|
+
auth_service.MendAuthSevice.connect().then(next).catch((err) => {
|
|
32
|
+
const errorMessage = err instanceof Error ? err?.message : err?.statusText;
|
|
33
|
+
logger.error(errorMessage || "Oops! Unauthorized");
|
|
34
|
+
response.status(err?.status || 401).json({ error: err?.statusText || "Oops! Unauthorized" });
|
|
32
35
|
});
|
|
33
36
|
};
|
|
34
|
-
const baseUrl = config.getString("mend.baseUrl");
|
|
35
37
|
const activationKey = config.getString("mend.activationKey");
|
|
36
38
|
const mendDataService = new data_service.MendDataService({
|
|
37
|
-
|
|
39
|
+
apiVersion: constants.MEND_API_VERSION,
|
|
38
40
|
activationKey
|
|
39
41
|
});
|
|
40
42
|
const catalogClient$1 = new catalogClient.CatalogClient({ discoveryApi: discovery });
|
|
@@ -123,10 +125,15 @@ async function createRouter(options) {
|
|
|
123
125
|
projectResult[0].items,
|
|
124
126
|
items || projectResult[1]
|
|
125
127
|
);
|
|
128
|
+
const entityURL = data_service_helpers.parseEntityURL(
|
|
129
|
+
projectResult[0].items[0]?.metadata?.annotations?.["backstage.io/source-location"]
|
|
130
|
+
);
|
|
131
|
+
const projectSourceUrl = entityURL?.host ? `${entityURL.host}${entityURL.path}` : "";
|
|
126
132
|
if (!data.length) {
|
|
127
133
|
response.json({
|
|
128
134
|
findingList: [],
|
|
129
135
|
projectList: [],
|
|
136
|
+
projectSourceUrl,
|
|
130
137
|
clientUrl: auth_service.MendAuthSevice.getClientUrl(),
|
|
131
138
|
clientName: auth_service.MendAuthSevice.getClientName()
|
|
132
139
|
});
|
|
@@ -177,6 +184,7 @@ async function createRouter(options) {
|
|
|
177
184
|
response.json({
|
|
178
185
|
findingList,
|
|
179
186
|
...projects,
|
|
187
|
+
projectSourceUrl,
|
|
180
188
|
clientUrl: auth_service.MendAuthSevice.getClientUrl(),
|
|
181
189
|
clientName: auth_service.MendAuthSevice.getClientName()
|
|
182
190
|
});
|
|
@@ -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} 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';\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(() => {\n response.status(401).json({ error: 'Oops! Unauthorized' });\n });\n };\n\n const baseUrl = config.getString('mend.baseUrl');\n const activationKey = config.getString('mend.activationKey');\n\n // Init api service\n const mendDataService = new MendDataService({\n baseUrl,\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 if (!data.length) {\n response.json({\n findingList: [],\n projectList: [],\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 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","catalogClient","CatalogClient","fetchQueryPagination","mendReadPermission","AuthorizeResult","transformConditions","dataMatcher","dataProjectParser","dataFindingParser","MiddlewareFactory"],"mappings":"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"}
|
|
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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-mend-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"main": "dist/index.cjs.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"postpack": "backstage-cli package postpack"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@backstage/backend-defaults": "^0.12.
|
|
41
|
-
"@backstage/backend-plugin-api": "^1.4.
|
|
42
|
-
"@backstage/catalog-client": "^1.
|
|
40
|
+
"@backstage/backend-defaults": "^0.12.1",
|
|
41
|
+
"@backstage/backend-plugin-api": "^1.4.3",
|
|
42
|
+
"@backstage/catalog-client": "^1.12.0",
|
|
43
43
|
"@backstage/catalog-model": "^1.7.5",
|
|
44
44
|
"@backstage/config": "^1.3.3",
|
|
45
45
|
"@backstage/plugin-permission-common": "^0.9.1",
|
|
46
|
-
"@backstage/plugin-permission-node": "^0.10.
|
|
46
|
+
"@backstage/plugin-permission-node": "^0.10.4",
|
|
47
47
|
"@types/express": "*",
|
|
48
48
|
"express": "^4.17.1",
|
|
49
49
|
"express-promise-router": "^4.1.0",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"zod": "^3.23.8"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@backstage/backend-test-utils": "^1.
|
|
59
|
-
"@backstage/cli": "^0.34.
|
|
60
|
-
"@backstage/plugin-auth-backend": "^0.25.
|
|
61
|
-
"@backstage/plugin-auth-backend-module-guest-provider": "^0.2.
|
|
58
|
+
"@backstage/backend-test-utils": "^1.9.0",
|
|
59
|
+
"@backstage/cli": "^0.34.3",
|
|
60
|
+
"@backstage/plugin-auth-backend": "^0.25.4",
|
|
61
|
+
"@backstage/plugin-auth-backend-module-guest-provider": "^0.2.12",
|
|
62
62
|
"@types/supertest": "^2.0.12",
|
|
63
63
|
"msw": "^1.0.0",
|
|
64
64
|
"supertest": "^6.2.4"
|