Skip to content
This repository was archived by the owner on Dec 24, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 41 additions & 4 deletions example/Nullify Demo Dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@
"queryParameters": {
"githubRepositoryIdsOrQueries": [
"$repository"
],
"ownerNamesOrQueries": [
"$owner"
]
},
"refId": "A"
Expand Down Expand Up @@ -359,7 +362,8 @@
"queryParameters": {
"githubRepositoryIdsOrQueries": [
"$repository"
]
],
"ownerNamesOrQueries": []
},
"refId": "A"
}
Expand Down Expand Up @@ -548,6 +552,9 @@
"queryParameters": {
"githubRepositoryIdsOrQueries": [
"$repository"
],
"ownerNamesOrQueries": [
"$owner"
]
},
"refId": "A"
Expand Down Expand Up @@ -719,7 +726,8 @@
],
"githubRepositoryIdsOrQueries": [
"$repository"
]
],
"ownerNamesOrQueries": []
},
"refId": "A"
}
Expand Down Expand Up @@ -845,6 +853,9 @@
"queryParameters": {
"githubRepositoryIdsOrQueries": [
"$repository"
],
"ownerNamesOrQueries": [
"$owner"
]
},
"refId": "A"
Expand Down Expand Up @@ -1269,6 +1280,9 @@
"queryParameters": {
"githubRepositoryIdsOrQueries": [
"$repository"
],
"ownerNamesOrQueries": [
"$owner"
]
},
"refId": "A"
Expand Down Expand Up @@ -1642,7 +1656,7 @@
"uid": "${DS_NULLIFY_DATASOURCE}"
},
"definition": "Nullify Repository Query",
"description": "Filter for the repositories for which to query data",
"description": "Filter repositories for which to query data",
"hide": 0,
"includeAll": true,
"label": "Repository",
Expand All @@ -1657,6 +1671,29 @@
"skipUrlSync": false,
"sort": 0,
"type": "query"
},
{
"current": {},
"datasource": {
"type": "nullify-grafana-datasource",
"uid": "${DS_NULLIFY_DATASOURCE}"
},
"definition": "Nullify Owner Query",
"description": "Filter code owners for which to query data",
"hide": 0,
"includeAll": true,
"label": "Owner",
"multi": true,
"name": "owner",
"options": [],
"query": {
"queryType": "Owner"
},
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
}
]
},
Expand All @@ -1668,6 +1705,6 @@
"timezone": "",
"title": "Nullify Demo Dashboard",
"uid": "ecf0f5c8-bf81-479a-b72f-94b5c2855d04",
"version": 15,
"version": 3,
"weekStart": ""
}
46 changes: 46 additions & 0 deletions src/api/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { z } from 'zod';

export const FileOwnerSchema = z.object({
name: z.string(),
type: z.string(),
});
export type FileOwner = z.infer<typeof FileOwnerSchema>;

export const RepositorySchema = z.object({
id: z.number(),
name: z.string(),
fullName: z.string(),
visibility: z.string(),
owner: z.object({
id: z.number(),
name: z.string(),
slug: z.string(),
type: z.string(),
}),
});
export type Repository = z.infer<typeof RepositorySchema>;

export const TeamSchema = z.object({
id: z.number(),
name: z.string(),
slug: z.string(),
privacy: z.string(),
numMembers: z.number(),
});
export type Team = z.infer<typeof TeamSchema>;

export const UserSchema = z.object({
id: z.number(),
name: z.string(),
slug: z.string(),
});
export type User = z.infer<typeof UserSchema>;

export const OrganizationSchema = z.object({
id: z.number(),
name: z.string(),
slug: z.string(),
teams: z.array(TeamSchema),
members: z.array(UserSchema),
});
export type Organization = z.infer<typeof OrganizationSchema>;
2 changes: 2 additions & 0 deletions src/api/sastCommon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from 'zod';
import { FileOwnerSchema } from './common';

export const SastFinding = z.object({
tenantId: z.string(),
Expand All @@ -17,4 +18,5 @@ export const SastFinding = z.object({
startLine: z.number(),
endLine: z.number(),
isAllowlisted: z.boolean(),
fileOwners: z.array(FileOwnerSchema).nullable(),
});
8 changes: 7 additions & 1 deletion src/api/sastEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataFrame, FieldType, TimeRange, createDataFrame } from '@grafana/data'
import { FetchResponse, isFetchError } from '@grafana/runtime';
import { SastEventType, SastEventsQueryOptions } from 'types';
import { SastFinding } from './sastCommon';
import { unwrapRepositoryTemplateVariables } from 'utils/utils';
import { unwrapOwnerTemplateVariables, unwrapRepositoryTemplateVariables } from 'utils/utils';

const MAX_API_REQUESTS = 10;

Expand Down Expand Up @@ -259,6 +259,7 @@ type SastEventsEvent = z.infer<typeof SastEventsEventSchema>;

interface SastEventsApiRequest {
githubRepositoryId?: number[];
fileOwnerName?: string[];
branch?: string;
eventType?: string[];
fromTime?: string; // ISO string
Expand All @@ -283,6 +284,11 @@ export const processSastEvents = async (
),
}
: {}),
...(queryOptions.queryParameters.ownerNamesOrQueries
? {
fileOwnerName: unwrapOwnerTemplateVariables(queryOptions.queryParameters.ownerNamesOrQueries),
}
: {}),
...(queryOptions.queryParameters.branch ? { branch: queryOptions.queryParameters.branch } : {}),
...(queryOptions.queryParameters.eventTypes && queryOptions.queryParameters.eventTypes.length > 0
? { eventType: queryOptions.queryParameters.eventTypes }
Expand Down
20 changes: 18 additions & 2 deletions src/api/sastSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';
import { DataFrame, FieldType, createDataFrame } from '@grafana/data';
import { FetchResponse } from '@grafana/runtime';
import { SastSummaryQueryOptions } from 'types';
import { prepend_severity_idx, unwrapRepositoryTemplateVariables } from 'utils/utils';
import { prepend_severity_idx, unwrapOwnerTemplateVariables, unwrapRepositoryTemplateVariables } from 'utils/utils';
import { SastFinding } from './sastCommon';

const SastSummaryApiResponseSchema = z.object({
Expand All @@ -12,6 +12,7 @@ const SastSummaryApiResponseSchema = z.object({

interface SastSummaryApiRequest {
githubRepositoryId?: number[];
fileOwnerName?: string[];
severity?: string;
}

Expand All @@ -27,6 +28,11 @@ export const processSastSummary = async (
),
}
: {}),
...(queryOptions.queryParameters.ownerNamesOrQueries
? {
fileOwnerName: unwrapOwnerTemplateVariables(queryOptions.queryParameters.ownerNamesOrQueries),
}
: {}),
...(queryOptions.queryParameters.severity ? { severity: queryOptions.queryParameters.severity } : {}),
};
const endpointPath = 'sast/summary';
Expand Down Expand Up @@ -85,10 +91,20 @@ export const processSastSummary = async (
values: parseResult.data.vulnerabilities.map((vuln) => vuln.isAllowlisted),
},
{
name: 'repositoryName',
name: 'repository',
type: FieldType.string,
values: parseResult.data.vulnerabilities.map((vuln) => vuln.repository),
},
{
name: 'branch',
type: FieldType.string,
values: parseResult.data.vulnerabilities.map((vuln) => vuln.branch),
},
{
name: 'owners',
type: FieldType.string,
values: parseResult.data.vulnerabilities.map((vuln) => vuln.fileOwners?.map((owner) => owner.name).join(', ')),
},
],
});
};
4 changes: 4 additions & 0 deletions src/api/scaCommon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from 'zod';
import { FileOwnerSchema } from './common';

const ScaEventsCve = z.object({
id: z.string().optional(),
Expand Down Expand Up @@ -30,11 +31,14 @@ export const ScaEventsDependencyFinding = z.object({
packageFilePath: z.string().optional(),
version: z.string().optional(),
filePath: z.string().optional(),
repository: z.string().optional(),
branch: z.string().optional(),
line: z.number().optional(),
numCritical: z.number().default(0),
numHigh: z.number().default(0),
numMedium: z.number().default(0),
numLow: z.number().default(0),
numUnknown: z.number().default(0),
vulnerabilities: z.array(ScaEventsVulnerability).optional().nullable(),
fileOwners: z.array(FileOwnerSchema).nullable(),
});
8 changes: 7 additions & 1 deletion src/api/scaEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataFrame, FieldType, TimeRange, createDataFrame } from '@grafana/data'
import { FetchResponse } from '@grafana/runtime';
import { ScaEventType, ScaEventsQueryOptions } from 'types';
import { ScaEventsDependencyFinding } from './scaCommon';
import { unwrapRepositoryTemplateVariables } from 'utils/utils';
import { unwrapOwnerTemplateVariables, unwrapRepositoryTemplateVariables } from 'utils/utils';

const MAX_API_REQUESTS = 10;

Expand Down Expand Up @@ -208,6 +208,7 @@ type ScaEventsEvent = z.infer<typeof ScaEventsEventSchema>;

interface ScaEventsApiRequest {
githubRepositoryId?: number[];
fileOwnerName?: string[];
branch?: string;
eventType?: string[];
fromTime?: string; // ISO string
Expand All @@ -232,6 +233,11 @@ export const processScaEvents = async (
),
}
: {}),
...(queryOptions.queryParameters.ownerNamesOrQueries
? {
fileOwnerName: unwrapOwnerTemplateVariables(queryOptions.queryParameters.ownerNamesOrQueries),
}
: {}),
...(queryOptions.queryParameters.branch ? { branch: queryOptions.queryParameters.branch } : {}),
...(queryOptions.queryParameters.eventTypes && queryOptions.queryParameters.eventTypes.length > 0
? { eventType: queryOptions.queryParameters.eventTypes }
Expand Down
33 changes: 30 additions & 3 deletions src/api/scaSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataFrame, FieldType, createDataFrame } from '@grafana/data';
import { FetchResponse } from '@grafana/runtime';
import { ScaSummaryQueryOptions } from 'types';
import { ScaEventsDependencyFinding } from './scaCommon';
import { unwrapRepositoryTemplateVariables } from 'utils/utils';
import { unwrapOwnerTemplateVariables, unwrapRepositoryTemplateVariables } from 'utils/utils';

const ScaSummaryApiResponseSchema = z.object({
vulnerabilities: z.array(ScaEventsDependencyFinding).nullable(),
Expand All @@ -12,6 +12,7 @@ const ScaSummaryApiResponseSchema = z.object({

interface ScaSummaryApiRequest {
githubRepositoryId?: number[];
fileOwnerName?: string[];
severity?: string;
}

Expand All @@ -28,6 +29,9 @@ export interface UnwoundScaEventsDependencyFinding {
numMedium: number | undefined;
numLow: number | undefined;
numUnknown: number | undefined;
repository: string | undefined;
branch: string | undefined;
owners: string[] | undefined;
vulnerabilityHasFix: boolean | undefined;
vulnerabilityTitle: string | undefined;
vulnerabilitySeverity: string | undefined;
Expand All @@ -50,6 +54,11 @@ export const processScaSummary = async (
),
}
: {}),
...(queryOptions.queryParameters.ownerNamesOrQueries
? {
fileOwnerName: unwrapOwnerTemplateVariables(queryOptions.queryParameters.ownerNamesOrQueries),
}
: {}),
...(queryOptions.queryParameters.package ? { package: queryOptions.queryParameters.package } : {}),
};
const endpointPath = 'sca/summary';
Expand All @@ -69,7 +78,7 @@ export const processScaSummary = async (
};
}

const unwoundFindings = parseResult.data.vulnerabilities?.flatMap(finding => {
const unwoundFindings = parseResult.data.vulnerabilities?.flatMap((finding) => {
let result: UnwoundScaEventsDependencyFinding[] = [];
for (const vuln of finding.vulnerabilities ?? []) {
result.push({
Expand All @@ -85,6 +94,9 @@ export const processScaSummary = async (
numMedium: finding.numMedium,
numLow: finding.numLow,
numUnknown: finding.numUnknown,
repository: finding.repository,
branch: finding.branch,
owners: finding.fileOwners?.map((owner) => owner.name),
vulnerabilityHasFix: vuln.hasFix,
vulnerabilityTitle: vuln.title,
vulnerabilitySeverity: vuln.severity,
Expand All @@ -95,7 +107,7 @@ export const processScaSummary = async (
vulnerabilityVersion: vuln.version,
});
}
return result
return result;
});

return createDataFrame({
Expand Down Expand Up @@ -151,6 +163,21 @@ export const processScaSummary = async (
type: FieldType.number,
values: unwoundFindings?.map((vuln) => vuln.numLow),
},
{
name: 'repository',
type: FieldType.string,
values: unwoundFindings?.map((vuln) => vuln.repository),
},
{
name: 'branch',
type: FieldType.string,
values: unwoundFindings?.map((vuln) => vuln.branch),
},
{
name: 'owners',
type: FieldType.string,
values: unwoundFindings?.map((vuln) => vuln.owners?.join(', ')),
},
{
name: 'vulnerabilityHasFix',
type: FieldType.boolean,
Expand Down
Loading