Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Db version representation #10

Merged
merged 36 commits into from
Mar 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e89810c
Update Neo4J schema to contain info about vulnerable components
Matej4545 Jan 23, 2023
4d48c85
Update Neo4J schema to contain info about vulnerable components
Matej4545 Jan 23, 2023
976a94a
Merge branch 'feature/filter-data' of https://github.com/Matej4545/de…
Matej4545 Jan 30, 2023
f72fd1e
FIltering works
Matej4545 Jan 31, 2023
47a9e44
New gitignore
Matej4545 Feb 3, 2023
d960c0f
WIP: Better import
Matej4545 Feb 6, 2023
12c242c
remove file
Matej4545 Feb 8, 2023
dd7a326
Add CORS support
Matej4545 Feb 8, 2023
3a4dcaa
Iproved import flow
Matej4545 Feb 8, 2023
de52799
ImportForm - define name and version
Matej4545 Feb 8, 2023
4598b05
WIP: Better import
Matej4545 Feb 6, 2023
23464a1
Fix import API endpoint
Feb 9, 2023
711c90a
WIP: Merge with filtering
Feb 10, 2023
3b34627
Merge branch 'improved-import' of https://github.com/Matej4545/depend…
Feb 10, 2023
6068a28
Exclude local .env files
Matej4545 Feb 10, 2023
e553b0f
WIP:
Matej4545 Feb 18, 2023
b59575a
Create DB contstraints
Matej4545 Feb 18, 2023
720b33b
Introduce ProjectVersion type in DB
Matej4545 Feb 18, 2023
e168ee0
Update types
Matej4545 Feb 18, 2023
0907c58
WIP: rewrite DBDataHelper
Matej4545 Feb 18, 2023
88a7bc7
WIP: Rewrite import
Matej4545 Feb 18, 2023
cb51961
Update types
Matej4545 Feb 20, 2023
ed4dbe1
WIP: continue with rewrite
Matej4545 Feb 20, 2023
f79224b
WIP: Fix some bugs with submission
Feb 22, 2023
5dc076f
WIP: Can create components
Matej4545 Feb 22, 2023
0c3f016
WIP: probably broken
Feb 24, 2023
2f002b6
Merge branch 'db-version-representation' of https://github.com/Matej4…
Matej4545 Feb 27, 2023
2dfbe45
Working
Mar 7, 2023
10f7321
Working import + vulnerabilities
Mar 8, 2023
d0eb41d
WIP: working upload + visualization
Mar 13, 2023
7664e5c
Graph cleanup
Mar 17, 2023
f0c629d
FInalize import - progress bar
Mar 18, 2023
228d49d
Colors improvement
Mar 19, 2023
a36f565
Vulnerability detail improvement
Mar 19, 2023
1d9543c
Link Improvement
Mar 19, 2023
c215562
Different endpoint for FE /BE
Mar 19, 2023
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
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ web_modules/
.yarn-integrity

# dotenv environment variable files
.env
.env*
.env.development.local
.env.test.local
.env.production.local
.env.local
.env*

# parcel-bundler cache (https://parceljs.org/)
.cache
Expand Down Expand Up @@ -134,4 +135,5 @@ dist

/runtime

*no_git*
*no_git*

36 changes: 28 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version: '3'
version: "3"

services:
neo4j:
image: neo4j:4.4.7
image: neo4j:latest
ports:
- 7474:7474
- 7687:7687
Expand All @@ -12,30 +12,50 @@ services:
- ./runtime/plugins:/var/lib/neo4j/plugins
restart: unless-stopped
environment:
- NEO4J_AUTH=neo4j/test
- NEO4J_AUTH=neo4j/${NEO4J_PASSWORD}
- NEO4J_apoc_export_file_enabled=true
- NEO4J_apoc_import_file_enabled=true
- NEO4J_apoc_import_file_use__neo4j__config=true
- NEO4JLABS_PLUGINS=["apoc"]
- NEO4J_dbms_security_procedures_unrestricted=apoc.*,algo.*

redis-cache:
image: redis:alpine
image: redis:latest
command: redis-server --requirepass ${REDIS_PASSWORD}
restart: unless-stopped
ports:
- 6379:6379
command: redis-server --save 20 1 --loglevel notice
volumes:
- cache:/data
ports:
- 6379:6379
links:
- redis-commander

redis-commander:
image: rediscommander/redis-commander:latest
restart: unless-stopped
environment:
REDIS_HOSTS: redis-cache
REDIS_HOST: redis-cache
REDIS_PORT: redis-cache:6379
REDIS_PASSWORD: ${REDIS_PASSWORD}
HTTP_USER: root
HTTP_PASSWORD: root
ports:
- 8081:8081

depvis-next:
depends_on:
- neo4j
- redis-cache
build: ./src/depvis-next
image: depvis-next:latest
ports:
- 80:3000
- 8123:3000
restart: always
environment:
NEO4J_PASSWORD: ${NEO4J_PASSWORD}
REDIS_PASSWORD: ${REDIS_PASSWORD}
NEXT_PUBLIC_SONATYPE_OSS_AUTH: ${SONATYPE_OSS_AUTH}
volumes:
cache:
driver: local
7 changes: 6 additions & 1 deletion src/depvis-next/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ node_modules
npm-debug.log
README.md
.next
.git
.git

.env.development.local
.env.test.local
.env.production.local
.env.local
13 changes: 0 additions & 13 deletions src/depvis-next/.env.production

This file was deleted.

2 changes: 1 addition & 1 deletion src/depvis-next/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev"
"command": "npm run dev --trace-warnings"
},
{
"name": "Next.js: debug client-side",
Expand Down
26 changes: 17 additions & 9 deletions src/depvis-next/components/Details/ComponentDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { gql, useQuery } from '@apollo/client';
import { Container } from 'react-bootstrap';
import { GetComponentRepositoryURL } from '../../helpers/WorkspaceHelper';
import Loading from '../Loading/Loading';
import { DL, DLItem } from './DescriptionList';
import { gql, useQuery } from "@apollo/client";
import { Container } from "react-bootstrap";
import { GetComponentRepositoryURL } from "../../helpers/WorkspaceHelper";
import Loading from "../Loading/Loading";
import { DL, DLItem } from "./DescriptionList";

const getComponentDetailsQuery = gql`
query componentDetails($componentPurl: String, $projectId: ID) {
components(where: { purl: $componentPurl, project_SINGLE: { id: $projectId } }) {
components(
where: { purl: $componentPurl, projectVersion: { id: $projectId } }
) {
name
purl
author
Expand All @@ -27,6 +29,7 @@ const ComponentDetails = (props) => {

const renderLink = () => {
const link = GetComponentRepositoryURL(data.components[0].purl);
if (!link) return;
return (
<a href={link} target="_blank" rel="noreferrer">
{link}
Expand All @@ -35,13 +38,15 @@ const ComponentDetails = (props) => {
};
if (loading) return <Loading />;
if (!data.components[0]) {
console.error('No data found when querying backend! Below is Apollo query result');
console.error(
"No data found when querying backend! Below is Apollo query result"
);
console.error({ data: data, error: error });
return <b>No data found!</b>;
}
const component = data.components[0];
return (
<Container style={{ wordBreak: 'break-all' }} className="px-0">
<Container style={{ wordBreak: "break-all" }} className="px-0">
<h4 className="pb-3">
<b>{component.name}</b>
</h4>
Expand All @@ -50,7 +55,10 @@ const ComponentDetails = (props) => {
<DLItem label="Author" value={component.author} />
<DLItem label="Publisher" value={component.publisher} />
<DLItem label="Purl" value={component.purl} />
<DLItem label="Number of dependencies" value={component.dependsOnCount} />
<DLItem
label="Number of dependencies"
value={component.dependsOnCount}
/>
<DLItem
label="Vulnerabilities"
value={component.vulnerabilities.map((v) => (
Expand Down
65 changes: 54 additions & 11 deletions src/depvis-next/components/Details/VulnerabilityDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { gql, useQuery } from '@apollo/client';
import { Badge, Container } from 'react-bootstrap';
import Loading from '../Loading/Loading';
import { DL, DLItem } from './DescriptionList';
import { gql, useQuery } from "@apollo/client";
import Link from "next/link";
import { Badge, Container } from "react-bootstrap";
import urlJoin from "url-join";
import { vulnerabilityColorByCVSS } from "../../helpers/GraphHelper";
import Loading from "../Loading/Loading";
import { DL, DLItem } from "./DescriptionList";

const getVulnerabilityDetailsQuery = gql`
query vulnerabilityDetails($vulnerabilityId: String) {
Expand Down Expand Up @@ -38,31 +41,71 @@ const VulnerabilityDetails = (props) => {
));
};

const getCvssScoreLabel = (cvssScore) => {
if (cvssScore >= 9) return "Critical";
if (cvssScore >= 7) return "High";
if (cvssScore >= 4) return "Medium";
return "Low";
};
const renderCvss = (cvssScore) => {
return <Badge bg={cvssScore > 5 ? 'danger' : 'warning'}>{cvssScore}</Badge>;
return (
<Badge
style={{
background: `${vulnerabilityColorByCVSS(cvssScore)}`,
}}
bg=""
>
{cvssScore} - {getCvssScoreLabel(cvssScore)}
</Badge>
);
};

const renderCvssVectorAsLink = (cvssVector) => {
const cvssPortalUrl = "https://www.first.org/cvss/calculator/3.1";
const url = `${cvssPortalUrl}#${cvssVector}`;
return (
<a href={url} target="_blank" rel="noreferrer">
{cvssVector}
</a>
);
};

if (loading) return <Loading />;
if (!data.vulnerabilities[0]) {
console.error('No data found when querying backend! Below is Apollo query result');
console.error(
"No data found when querying backend! Below is Apollo query result"
);
console.error({ data: data, error: error });
return <b>No data found!</b>;
}
const vulnerability = data.vulnerabilities[0];
return (
<Container style={{ wordBreak: 'break-word' }} className="px-0">
<Container style={{ wordBreak: "break-word" }} className="px-0">
<h4 className="pb-3">
<b>{vulnerability.name}</b>
</h4>
<DL>
<DLItem label="Id" value={vulnerability.id} />
<DLItem label="CVSS Score" value={renderCvss(vulnerability.cvssScore)} alwaysShow />
<DLItem label="CVSS Vector" value={vulnerability.cvssVector} />
<DLItem
label="CVSS Score"
value={renderCvss(vulnerability.cvssScore)}
alwaysShow
/>
<DLItem
label="CVSS Vector"
value={renderCvssVectorAsLink(vulnerability.cvssVector)}
/>
<DLItem label="Description" value={vulnerability.description} />

<DLItem label="affectedVersions" value={vulnerability.affectedVersions} />
<DLItem
label="affectedVersions"
value={vulnerability.affectedVersions}
/>
<DLItem label="CWE" value={vulnerability.cwe} />
<DLItem label="References" value={renderReferences(vulnerability.references)} />
<DLItem
label="References"
value={renderReferences(vulnerability.references)}
/>
</DL>
</Container>
);
Expand Down
37 changes: 25 additions & 12 deletions src/depvis-next/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
import { useState } from 'react';
import { Container, Form } from 'react-bootstrap';
import { useEffect, useState } from "react";
import { Container, Form } from "react-bootstrap";

export type DropdownItem = {
displayName: string;
id: string;
};

/**
* Dropdown component, renders set of options and fires a callback on change
* @param props one of title, onChange, defaultValue, options, disabled
* @returns
*/
export default function Dropdown(props) {
const [selected, setSelected] = useState(props.default);
const { title, onChange, defaultValue, options, disabled } = props;
const [selectedId, setSelectedId] = useState(defaultValue);
return (
<Container>
<Form>
{props.title && <Form.Label>{props.title}</Form.Label>}
{title && <Form.Label>{title}</Form.Label>}
<Form.Select
value={selected}
value={selectedId && selectedId}
disabled={disabled}
onChange={(e) => {
props.onChange(e.target.value);
setSelected(e.target.value);
setSelectedId(e.target.value);
onChange(e.target.value);
}}
>
{props.options.map((v, i) => (
<option key={i} value={v.id}>
{v.name}
</option>
))}
{options &&
options.map((v: DropdownItem, i: number) => (
<option key={i} value={v.id}>
{v.displayName}
</option>
))}
</Form.Select>
</Form>
</Container>
Expand Down
11 changes: 11 additions & 0 deletions src/depvis-next/components/Error/NoProjectFoundError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Link from 'next/link';
import { Container } from 'react-bootstrap';

export default function NoProjectFoundError(props) {
return (
<Container className="mx-auto my-5 text-center">
<p className="fs-4 fw-bold">No project found!</p>
<Link href="/upload">Upload SBOM</Link>
</Container>
);
}
17 changes: 9 additions & 8 deletions src/depvis-next/components/Graph/GraphConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export type GraphConfig = {
zoomLevel: number
color: string | Function,
label: string | Function,
linkDirectionalArrowLength: number,
linkDirectionalRelPos: number
nodeVal: number | Function
linkLength: number
}
zoomLevel: number;
color: string | Function;
label: string | Function;
linkDirectionalArrowLength: number;
linkDirectionalRelPos: number;
nodeVal: number | Function;
linkLength: number;
showOnlyVulnerable: Boolean;
};
Loading