diff --git a/.changeset/breezy-pigs-sell.md b/.changeset/breezy-pigs-sell.md new file mode 100644 index 000000000..3d2146974 --- /dev/null +++ b/.changeset/breezy-pigs-sell.md @@ -0,0 +1,7 @@ +--- +'@roadiehq/backstage-plugin-wiz': patch +'@roadiehq/plugin-wiz-backend': patch +'backend': patch +--- + +Handle missing parameters message, remove uneeded config property. Improve description in WIZ graphs diff --git a/app-config.yaml b/app-config.yaml index e6e5e15f2..757f8e474 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -232,6 +232,3 @@ bugsnag: iframe: allowList: ['example.com'] - -wiz: - enabled: false diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index c78c8c9fb..511fb42f0 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -99,14 +99,6 @@ async function main() { const argocdEnv = useHotMemoize(module, () => createEnv('argocd')); const wizEnv = useHotMemoize(module, () => createEnv('wiz')); - const wizConfig = { - enabled: config.getOptionalBoolean('wiz.enabled'), - clientId: config.getOptionalString('wiz.clientId'), - clientSecret: config.getOptionalString('wiz.clientSecret'), - tokenUrl: config.getOptionalString('wiz.tokenUrl'), - apiUrl: config.getOptionalString('wiz.wizAPIUrl'), - }; - const apiRouter = Router(); apiRouter.use('/catalog', await catalog(catalogEnv)); apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)); @@ -115,17 +107,7 @@ async function main() { apiRouter.use('/proxy', await proxy(proxyEnv)); apiRouter.use('/aws', await aws(awsEnv)); apiRouter.use('/argocd', await argocd(argocdEnv)); - - if ( - wizConfig.enabled && - wizConfig.clientId && - wizConfig.clientSecret && - wizConfig.tokenUrl && - wizConfig.apiUrl - ) { - apiRouter.use('/wiz-backend', await wiz(wizEnv)); - } - + apiRouter.use('/wiz-backend', await wiz(wizEnv)); apiRouter.use(notFoundHandler()); const service = createServiceBuilder(module) diff --git a/plugins/backend/wiz-backend/README.md b/plugins/backend/wiz-backend/README.md index 66f3222f0..6e8c48d62 100644 --- a/plugins/backend/wiz-backend/README.md +++ b/plugins/backend/wiz-backend/README.md @@ -23,11 +23,11 @@ After obtaining all of the above, add wiz configuration in your app-config.yaml ```yaml wiz: - enabled: true clientId: clientSecret: tokenUrl: wizAPIUrl: + dashboardLink: ``` Create a file in `packages/backend/src/plugins/wiz.ts` @@ -54,7 +54,6 @@ async function main() { const wizEnv = useHotMemoize(module, () => createEnv('wiz')); const wizConfig = { - enabled: config.getOptionalBoolean('wiz.enabled'), clientId: config.getOptionalString('wiz.clientId'), clientSecret: config.getOptionalString('wiz.clientSecret'), tokenUrl: config.getOptionalString('wiz.tokenUrl'), diff --git a/plugins/backend/wiz-backend/config.d.ts b/plugins/backend/wiz-backend/config.d.ts index d387d8258..be4a4f086 100644 --- a/plugins/backend/wiz-backend/config.d.ts +++ b/plugins/backend/wiz-backend/config.d.ts @@ -15,10 +15,6 @@ */ export interface Config { wiz?: { - /** - * @visibility frontend - */ - enabled?: boolean; /** * @visibility frontend */ diff --git a/plugins/backend/wiz-backend/src/plugin.ts b/plugins/backend/wiz-backend/src/plugin.ts index a801bf6b6..cf6e3cfca 100644 --- a/plugins/backend/wiz-backend/src/plugin.ts +++ b/plugins/backend/wiz-backend/src/plugin.ts @@ -40,10 +40,6 @@ export const wizBackendPlugin = createBackendPlugin({ config, }), ); - httpRouter.addAuthPolicy({ - path: '/health', - allow: 'unauthenticated', - }); }, }); }, diff --git a/plugins/backend/wiz-backend/src/service/WizClient.ts b/plugins/backend/wiz-backend/src/service/WizClient.ts index 6c16c91b7..a953b207e 100644 --- a/plugins/backend/wiz-backend/src/service/WizClient.ts +++ b/plugins/backend/wiz-backend/src/service/WizClient.ts @@ -26,10 +26,11 @@ export class WizClient { private tokenExpiresAt: number | null = null; constructor(config: Config) { - this.clientId = config.getString('wiz.clientId'); - this.clientSecret = config.getString('wiz.clientSecret'); - this.tokenUrl = config.getString('wiz.tokenUrl'); - this.wizAPIUrl = config.getString('wiz.wizAPIUrl'); + this.clientId = config.getOptionalString('wiz.clientId') ?? 'clientId'; + this.clientSecret = + config.getOptionalString('wiz.clientSecret') ?? 'clientSecret'; + this.tokenUrl = config.getOptionalString('wiz.tokenUrl') ?? 'tokenUrl'; + this.wizAPIUrl = config.getOptionalString('wiz.wizAPIUrl') ?? 'wizAPIUrl'; } async fetchAccessToken() { diff --git a/plugins/backend/wiz-backend/src/service/router.ts b/plugins/backend/wiz-backend/src/service/router.ts index 222d053e3..b96a63554 100644 --- a/plugins/backend/wiz-backend/src/service/router.ts +++ b/plugins/backend/wiz-backend/src/service/router.ts @@ -17,7 +17,7 @@ import { LoggerService, RootConfigService, } from '@backstage/backend-plugin-api'; -import express from 'express'; +import express, { Request, Response, NextFunction } from 'express'; import Router from 'express-promise-router'; import { WizClient } from './WizClient'; @@ -26,6 +26,40 @@ export interface RouterOptions { config: RootConfigService; } +function validateWizConfig(config: any) { + return (_req: Request, res: Response, next: NextFunction): void => { + const wizConfig = { + clientId: config.getOptionalString('wiz.clientId'), + clientSecret: config.getOptionalString('wiz.clientSecret'), + tokenUrl: config.getOptionalString('wiz.tokenUrl'), + apiUrl: config.getOptionalString('wiz.wizAPIUrl'), + }; + + if (!wizConfig.clientId || !wizConfig.clientSecret) { + res.status(401).send({ + error: 'Not authenticated, missing Client Secret or Client ID.', + }); + return; + } + + if (!wizConfig.tokenUrl) { + res.status(400).send({ + error: 'Missing token URL.', + }); + return; + } + + if (!wizConfig.apiUrl) { + res.status(400).send({ + error: 'Missing API endpoint URL', + }); + return; + } + + next(); + }; +} + export async function createRouter( options: RouterOptions, ): Promise { @@ -34,10 +68,11 @@ export async function createRouter( const router = Router(); const wizAuthClient = new WizClient(config); - await wizAuthClient.fetchAccessToken(); + router.use(validateWizConfig(config)); router.get('/wiz-issues/:projectId', async (req, res) => { try { + await wizAuthClient.fetchAccessToken(); const data = await wizAuthClient.getIssuesForProject( req.params.projectId, ); @@ -53,8 +88,10 @@ export async function createRouter( error: error.message, }); } - return res.status(500).send({ - error: 'Failed to fetch issues for project', + return res.status(error.statusCode).send({ + error: + error.message ?? + 'There was an error fetching issues for this project', }); } }); diff --git a/plugins/frontend/backstage-plugin-wiz/README.md b/plugins/frontend/backstage-plugin-wiz/README.md index ba746fb6c..33cd3aa70 100644 --- a/plugins/frontend/backstage-plugin-wiz/README.md +++ b/plugins/frontend/backstage-plugin-wiz/README.md @@ -77,7 +77,6 @@ In order to add correct url which will lead to WIZ dashboard for your organisati ```yaml wiz: - enabled: true dashboardLink: clientId: clientSecret: diff --git a/plugins/frontend/backstage-plugin-wiz/docs/issues-chart.png b/plugins/frontend/backstage-plugin-wiz/docs/issues-chart.png index 8d4f505ec..47ada48ed 100644 Binary files a/plugins/frontend/backstage-plugin-wiz/docs/issues-chart.png and b/plugins/frontend/backstage-plugin-wiz/docs/issues-chart.png differ diff --git a/plugins/frontend/backstage-plugin-wiz/docs/issues-widget.png b/plugins/frontend/backstage-plugin-wiz/docs/issues-widget.png index 76af6ebd4..3afc5cb54 100644 Binary files a/plugins/frontend/backstage-plugin-wiz/docs/issues-widget.png and b/plugins/frontend/backstage-plugin-wiz/docs/issues-widget.png differ diff --git a/plugins/frontend/backstage-plugin-wiz/docs/severity-graph.png b/plugins/frontend/backstage-plugin-wiz/docs/severity-graph.png index 7647b301b..69db7ef0c 100644 Binary files a/plugins/frontend/backstage-plugin-wiz/docs/severity-graph.png and b/plugins/frontend/backstage-plugin-wiz/docs/severity-graph.png differ diff --git a/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/IssuesChart.tsx b/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/IssuesChart.tsx index 2cfe234e0..85deb7ae1 100644 --- a/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/IssuesChart.tsx +++ b/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/IssuesChart.tsx @@ -43,6 +43,7 @@ export const IssuesChart = () => { return ( , classes: { diff --git a/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/LineChart.tsx b/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/LineChart.tsx index c90297f5f..a36af3a78 100644 --- a/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/LineChart.tsx +++ b/plugins/frontend/backstage-plugin-wiz/src/components/EntityIssuesChart/LineChart.tsx @@ -19,8 +19,14 @@ import { ResponsiveLine } from '@nivo/line'; import { WizIssue } from '../Issues/types'; import { useTheme } from '@material-ui/core'; +const issueStatusFilters = { + openIssues: 'OPEN', + resolvedIssues: 'RESOLVED', +}; + export const LineChart = ({ issues }: { issues: WizIssue[] }) => { const theme = useTheme(); + const transformIssuesForChart = () => { const monthMap: Record = {}; @@ -28,16 +34,9 @@ export const LineChart = ({ issues }: { issues: WizIssue[] }) => { sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6); issues?.forEach( - (issue: { - createdAt: string | number | Date; - resolvedAt: string | number | Date; - }) => { + (issue: { status: string; createdAt: string | number | Date }) => { const createdAtDate = new Date(issue.createdAt); - const resolvedAtDate = issue.resolvedAt - ? new Date(issue.resolvedAt) - : null; - // Filter based on createdAt if (createdAtDate >= sixMonthsAgo) { const createdAtMonth = createdAtDate.toLocaleString('default', { month: 'short', @@ -47,19 +46,12 @@ export const LineChart = ({ issues }: { issues: WizIssue[] }) => { if (!monthMap[createdAtMonth]) { monthMap[createdAtMonth] = { open: 0, resolved: 0 }; } - monthMap[createdAtMonth].open += 1; - } - - if (resolvedAtDate && resolvedAtDate >= sixMonthsAgo) { - const resolvedAtMonth = resolvedAtDate.toLocaleString('default', { - month: 'short', - year: 'numeric', - }); - if (!monthMap[resolvedAtMonth]) { - monthMap[resolvedAtMonth] = { open: 0, resolved: 0 }; + if (issue.status === issueStatusFilters.openIssues) { + monthMap[createdAtMonth].open += 1; + } else if (issue.status === issueStatusFilters.resolvedIssues) { + monthMap[createdAtMonth].resolved += 1; } - monthMap[resolvedAtMonth].resolved += 1; } }, ); diff --git a/plugins/frontend/backstage-plugin-wiz/src/components/EntitySeverityChart/SeverityChart.tsx b/plugins/frontend/backstage-plugin-wiz/src/components/EntitySeverityChart/SeverityChart.tsx index 98b694fd5..3c8f6f6c6 100644 --- a/plugins/frontend/backstage-plugin-wiz/src/components/EntitySeverityChart/SeverityChart.tsx +++ b/plugins/frontend/backstage-plugin-wiz/src/components/EntitySeverityChart/SeverityChart.tsx @@ -42,7 +42,8 @@ export const SeverityChart = () => { return ( , classes: { diff --git a/plugins/frontend/backstage-plugin-wiz/src/components/IssuesWidget/IssuesWidget.tsx b/plugins/frontend/backstage-plugin-wiz/src/components/IssuesWidget/IssuesWidget.tsx index bcd9a9d96..b9d922f56 100644 --- a/plugins/frontend/backstage-plugin-wiz/src/components/IssuesWidget/IssuesWidget.tsx +++ b/plugins/frontend/backstage-plugin-wiz/src/components/IssuesWidget/IssuesWidget.tsx @@ -112,14 +112,18 @@ export const IssuesWidget = () => { root: classes.card, }, }} - deepLink={{ - link: `https://${dashboardLink}`, - title: 'Go to WIZ', - onClick: e => { - e.preventDefault(); - window.open(`https://${dashboardLink}`); - }, - }} + deepLink={ + dashboardLink + ? { + link: `https://${dashboardLink}`, + title: 'Go to your WIZ dashboard', + onClick: e => { + e.preventDefault(); + window.open(`https://${dashboardLink}`); + }, + } + : undefined + } > {' '} {value && value.length > 0 ? ( @@ -131,7 +135,7 @@ export const IssuesWidget = () => { display="flex" mt={2} flexDirection="column" - width="9vw" + width="8.5vw" style={{ backgroundColor: theme.palette.background.default, }} @@ -186,7 +190,7 @@ export const IssuesWidget = () => { display="flex" mt={2} flexDirection="column" - width="9vw" + width="8.5vw" style={{ backgroundColor: theme.palette.background.default, }} @@ -241,7 +245,7 @@ export const IssuesWidget = () => { display="flex" mt={2} flexDirection="column" - width="9vw" + width="8.5vw" style={{ backgroundColor: theme.palette.background.default, }} @@ -296,7 +300,7 @@ export const IssuesWidget = () => { display="flex" mt={2} flexDirection="column" - width="9vw" + width="8.5vw" style={{ backgroundColor: theme.palette.background.default, }}