Added signature and vulnerabilities in RepoCard, PreviewCard, RepoDetails and TagDetails with uses and used by tabs

Signed-off-by: Amelia-Maria Breda <ambreda@cisco.com>
This commit is contained in:
Amelia-Maria Breda 2022-10-17 17:13:40 +01:00 committed by Raul Kele
parent 4d339506b2
commit 4446aa03c7
16 changed files with 1041 additions and 89 deletions

View File

@ -30,10 +30,14 @@ const mockImageList = {
NewestImage: {
Tag: 'latest',
Description: 'w',
IsSigned: true,
IsSigned: false,
Licenses: '',
Vendor: '',
Labels: ''
Labels: '',
Vulnerabilities: {
MaxSeverity: 'LOW',
Count: 7
}
}
},
{
@ -43,23 +47,82 @@ const mockImageList = {
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: false,
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: ''
Labels: '',
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 2
}
}
},
{
Name: 'nodeUnique',
Name: 'node',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: false,
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: ''
Labels: '',
Vulnerabilities: {
MaxSeverity: 'CRITICAL',
Count: 10
}
}
},
{
Name: 'centos',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'NONE',
Count: 10
}
}
},
{
Name: 'debian',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'MEDIUM',
Count: 10
}
}
},
{
Name: 'mysql',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'UNKNOWN',
Count: 10
}
}
}
]
@ -77,7 +140,7 @@ describe('Explore component', () => {
render(<StateExploreWrapper />);
expect(await screen.findByText(/alpine/i)).toBeInTheDocument();
expect(await screen.findByText(/mongo/i)).toBeInTheDocument();
expect(await screen.findByText(/nodeUnique/i)).toBeInTheDocument();
expect(await screen.findByText(/centos/i)).toBeInTheDocument();
});
it('displays the no data message if no data is received', async () => {
@ -91,8 +154,20 @@ describe('Explore component', () => {
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
render(<StateExploreWrapper />);
expect(await screen.findAllByTestId('unverified-chip')).toHaveLength(2);
expect(await screen.findAllByTestId('verified-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('unverified-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('verified-chip')).toHaveLength(5);
});
it('renders vulnerability chips', async () => {
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
render(<StateExploreWrapper />);
expect(await screen.findAllByTestId('low-vulnerability-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('high-vulnerability-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('critical-vulnerability-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('none-vulnerability-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('medium-vulnerability-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('unknown-vulnerability-chip')).toHaveLength(1);
});
it("should log an error when data can't be fetched", async () => {

View File

@ -23,7 +23,11 @@ const mockImageList = {
IsSigned: false,
Licenses: '',
Vendor: '',
Labels: ''
Labels: '',
Vulnerabilities: {
MaxSeverity: 'LOW',
Count: 7
}
}
},
{
@ -36,7 +40,11 @@ const mockImageList = {
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: ''
Labels: '',
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 2
}
}
},
{
@ -49,7 +57,62 @@ const mockImageList = {
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: ''
Labels: '',
Vulnerabilities: {
MaxSeverity: 'CRITICAL',
Count: 10
}
}
},
{
Name: 'centos',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'NONE',
Count: 10
}
}
},
{
Name: 'debian',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'MEDIUM',
Count: 10
}
}
},
{
Name: 'mysql',
Size: '369311301',
LastUpdated: '2022-08-23T00:20:40.144281895Z',
NewestImage: {
Tag: 'latest',
Description: '',
IsSigned: true,
Licenses: '',
Vendor: '',
Labels: '',
Vulnerabilities: {
MaxSeverity: 'UNKNOWN',
Count: 10
}
}
}
]
@ -79,11 +142,21 @@ describe('Home component', () => {
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
render(<Home />);
expect(await screen.findAllByTestId('unverified-icon')).toHaveLength(1);
expect(await screen.findAllByTestId('verified-icon')).toHaveLength(2);
expect(await screen.findAllByTestId('verified-icon')).toHaveLength(3);
expect(await screen.findAllByTestId('unverified-chip')).toHaveLength(1);
expect(await screen.findAllByTestId('verified-chip')).toHaveLength(1);
});
it('renders vulnerability icons', async () => {
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
render(<Home />);
expect(await screen.findAllByTestId('low-vulnerability-icon')).toHaveLength(1);
expect(await screen.findAllByTestId('high-vulnerability-icon')).toHaveLength(1);
expect(await screen.findAllByTestId('critical-vulnerability-icon')).toHaveLength(1);
expect(await screen.findAllByTestId('none-vulnerability-icon')).toHaveLength(1);
});
it("should log an error when data can't be fetched", async () => {
// @ts-ignore
jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} });

View File

@ -19,23 +19,138 @@ jest.mock('react-router-dom', () => ({
},
useLocation: () => {
return mockUseLocationValue;
}
},
useNavigate: () => jest.fn()
}));
const mockRepoDetailsData = {
ExpandedRepoInfo: {
Manifests: [
Images: [
{
Digest: '2aa7ff5ca352d4d25fc6548f9930a436aacd64d56b1bd1f9ff4423711b9c8718',
Tag: 'latest',
Layers: [
{
Size: '2798889',
Digest: '2408cc74d12b6cd092bb8b516ba7d5e290f485d3eb9672efc00f0583730179e8'
}
]
Tag: 'latest'
}
]
],
Summary: {
Name: 'test',
NewestImage: {
RepoName: 'mongo',
IsSigned: true,
Vulnerabilities: {
MaxSeverity: 'CRITICAL',
Count: 15
}
}
}
}
};
const mockRepoDetailsNone = {
ExpandedRepoInfo: {
Images: [
{
Digest: '2aa7ff5ca352d4d25fc6548f9930a436aacd64d56b1bd1f9ff4423711b9c8718',
Tag: 'latest'
}
],
Summary: {
Name: 'test1',
NewestImage: {
RepoName: 'mongo',
IsSigned: true,
Vulnerabilities: {
MaxSeverity: 'NONE',
Count: 15
}
}
}
}
};
const mockRepoDetailsUnknown = {
ExpandedRepoInfo: {
Images: [
{
Digest: '2aa7ff5ca352d4d25fc6548f9930a436aacd64d56b1bd1f9ff4423711b9c8718',
Tag: 'latest'
}
],
Summary: {
Name: 'test1',
NewestImage: {
RepoName: 'mongo',
IsSigned: true,
Vulnerabilities: {
MaxSeverity: 'UNKNOWN',
Count: 15
}
}
}
}
};
const mockRepoDetailsLow = {
ExpandedRepoInfo: {
Images: [
{
Digest: '2aa7ff5ca352d4d25fc6548f9930a436aacd64d56b1bd1f9ff4423711b9c8718',
Tag: 'latest'
}
],
Summary: {
Name: 'test1',
NewestImage: {
RepoName: 'mongo',
IsSigned: true,
Vulnerabilities: {
MaxSeverity: 'LOW',
Count: 15
}
}
}
}
};
const mockRepoDetailsMedium = {
ExpandedRepoInfo: {
Images: [
{
Digest: '2aa7ff5ca352d4d25fc6548f9930a436aacd64d56b1bd1f9ff4423711b9c8718',
Tag: 'latest'
}
],
Summary: {
Name: 'test1',
NewestImage: {
RepoName: 'mongo',
IsSigned: true,
Vulnerabilities: {
MaxSeverity: 'MEDIUM',
Count: 15
}
}
}
}
};
const mockRepoDetailsHigh = {
ExpandedRepoInfo: {
Images: [
{
Digest: '2aa7ff5ca352d4d25fc6548f9930a436aacd64d56b1bd1f9ff4423711b9c8718',
Tag: 'latest'
}
],
Summary: {
Name: 'test1',
NewestImage: {
RepoName: 'mongo',
IsSigned: true,
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 15
}
}
}
}
};
@ -52,6 +167,33 @@ describe('Repo details component', () => {
expect(await screen.findByText('test')).toBeInTheDocument();
});
it('renders vulnerability chips', async () => {
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsData } });
render(<RepoDetails />);
expect(await screen.findAllByTestId('critical-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsNone } });
render(<RepoDetails />);
expect(await screen.findAllByTestId('none-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsUnknown } });
render(<RepoDetails />);
expect(await screen.findAllByTestId('unknown-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsLow } });
render(<RepoDetails />);
expect(await screen.findAllByTestId('low-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsMedium } });
render(<RepoDetails />);
expect(await screen.findAllByTestId('medium-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsHigh } });
render(<RepoDetails />);
expect(await screen.findAllByTestId('high-vulnerability-chip')).toHaveLength(1);
});
it("should log error if data can't be fetched", async () => {
jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} });
const error = jest.spyOn(console, 'error').mockImplementation(() => {});

View File

@ -9,19 +9,35 @@ const mockDependenciesList = {
BaseImageList: [
{
RepoName: 'project-stacker/c3/static-ubuntu-amd64',
Tag: 'tag1'
Tag: 'tag1',
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 5
}
},
{
RepoName: 'tag2',
Tag: 'tag2'
Tag: 'tag2',
Vulnerabilities: {
MaxSeverity: 'CRITICAL',
Count: 2
}
},
{
RepoName: 'tag3',
Tag: 'tag3'
Tag: 'tag3',
Vulnerabilities: {
MaxSeverity: 'LOW',
Count: 7
}
},
{
RepoName: 'tag4',
Tag: 'tag4'
Tag: 'tag4',
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 5
}
}
]
}

View File

@ -9,19 +9,35 @@ const mockDependentsList = {
DerivedImageList: [
{
RepoName: 'project-stacker/c3/static-ubuntu-amd64',
Tag: 'tag1'
Tag: 'tag1',
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 5
}
},
{
RepoName: 'tag2',
Tag: 'tag2'
Tag: 'tag2',
Vulnerabilities: {
MaxSeverity: 'CRITICAL',
Count: 2
}
},
{
RepoName: 'tag3',
Tag: 'tag3'
Tag: 'tag3',
Vulnerabilities: {
MaxSeverity: 'LOW',
Count: 5
}
},
{
RepoName: 'tag4',
Tag: 'tag4'
Tag: 'tag4',
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 3
}
}
]
}

View File

@ -15,6 +15,10 @@ const mockImage = {
Os: 'linux',
Arch: 'amd64'
},
Vulnerabilities: {
MaxSeverity: 'CRITICAL',
Count: 10
},
Vendor: 'CentOS',
History: [
{
@ -57,6 +61,106 @@ const mockImage = {
}
};
const mockImageNone = {
Image: {
RepoName: 'centos',
Tag: '8',
Digest: 'sha256:63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29',
LastUpdated: '2020-12-08T00:22:52.526672082Z',
Size: '75183423',
ConfigDigest: 'sha256:8dd57e171a61368ffcfde38045ddb6ed74a32950c271c1da93eaddfb66a77e78',
Platform: {
Os: 'linux',
Arch: 'amd64'
},
Vulnerabilities: {
MaxSeverity: 'NONE',
Count: 10
},
Vendor: 'CentOS'
}
};
const mockImageUnknown = {
Image: {
RepoName: 'centos',
Tag: '8',
Digest: 'sha256:63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29',
LastUpdated: '2020-12-08T00:22:52.526672082Z',
Size: '75183423',
ConfigDigest: 'sha256:8dd57e171a61368ffcfde38045ddb6ed74a32950c271c1da93eaddfb66a77e78',
Platform: {
Os: 'linux',
Arch: 'amd64'
},
Vulnerabilities: {
MaxSeverity: 'UNKNOWN',
Count: 10
},
Vendor: 'CentOS'
}
};
const mockImageLow = {
Image: {
RepoName: 'centos',
Tag: '8',
Digest: 'sha256:63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29',
LastUpdated: '2020-12-08T00:22:52.526672082Z',
Size: '75183423',
ConfigDigest: 'sha256:8dd57e171a61368ffcfde38045ddb6ed74a32950c271c1da93eaddfb66a77e78',
Platform: {
Os: 'linux',
Arch: 'amd64'
},
Vulnerabilities: {
MaxSeverity: 'LOW',
Count: 10
},
Vendor: 'CentOS'
}
};
const mockImageMedium = {
Image: {
RepoName: 'centos',
Tag: '8',
Digest: 'sha256:63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29',
LastUpdated: '2020-12-08T00:22:52.526672082Z',
Size: '75183423',
ConfigDigest: 'sha256:8dd57e171a61368ffcfde38045ddb6ed74a32950c271c1da93eaddfb66a77e78',
Platform: {
Os: 'linux',
Arch: 'amd64'
},
Vulnerabilities: {
MaxSeverity: 'MEDIUM',
Count: 10
},
Vendor: 'CentOS'
}
};
const mockImageHigh = {
Image: {
RepoName: 'centos',
Tag: '8',
Digest: 'sha256:63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29',
LastUpdated: '2020-12-08T00:22:52.526672082Z',
Size: '75183423',
ConfigDigest: 'sha256:8dd57e171a61368ffcfde38045ddb6ed74a32950c271c1da93eaddfb66a77e78',
Platform: {
Os: 'linux',
Arch: 'amd64'
},
Vulnerabilities: {
MaxSeverity: 'HIGH',
Count: 10
},
Vendor: 'CentOS'
}
};
// mock clipboard copy fn
const mockCopyToClipboard = jest.fn();
Object.assign(navigator, {
@ -104,6 +208,7 @@ describe('Tags details', () => {
render(<TagDetails />);
await waitFor(() => expect(error).toBeCalledTimes(1));
});
it('should show tag details metadata', async () => {
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImage } });
@ -111,6 +216,33 @@ describe('Tags details', () => {
expect(await screen.findByTestId('tagDetailsMetadata-container')).toBeInTheDocument();
});
it('renders vulnerability chips', async () => {
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImage } });
render(<TagDetails />);
expect(await screen.findAllByTestId('critical-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageNone } });
render(<TagDetails />);
expect(await screen.findAllByTestId('none-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageUnknown } });
render(<TagDetails />);
expect(await screen.findAllByTestId('unknown-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageLow } });
render(<TagDetails />);
expect(await screen.findAllByTestId('low-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageMedium } });
render(<TagDetails />);
expect(await screen.findAllByTestId('medium-vulnerability-chip')).toHaveLength(1);
// @ts-ignore
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageHigh } });
render(<TagDetails />);
expect(await screen.findAllByTestId('high-vulnerability-chip')).toHaveLength(1);
});
it('should copy the pull string to clipboard', async () => {
jest
.spyOn(api, 'get')

View File

@ -63,11 +63,11 @@ const endpoints = {
repoList: ({ pageNumber = 1, pageSize = 15 } = {}) =>
`/v2/_zot/ext/search?query={RepoListWithNewestImage(requestedPage: {limit:${pageSize} offset:${
(pageNumber - 1) * pageSize
}}){Name LastUpdated Size Platforms {Os Arch} NewestImage { Tag Description Licenses Logo Title Source IsSigned Documentation History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}} Vendor Labels} DownloadCount}}`,
}}){Name LastUpdated Size Platforms {Os Arch} NewestImage { Tag Vulnerabilities {MaxSeverity Count} Description Licenses Logo Title Source IsSigned Documentation History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}} Vendor Labels} DownloadCount}}`,
detailedRepoInfo: (name) =>
`/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Tag LastUpdated Vendor Size Platform {Os Arch} } Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestImage {RepoName Layers {Size Digest} Digest Tag Logo Title Documentation DownloadCount Source Description Licenses History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}}}}}}`,
`/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Vulnerabilities {MaxSeverity Count} Tag LastUpdated Vendor Size Platform {Os Arch}} Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestImage {RepoName IsSigned Vulnerabilities {MaxSeverity Count} Layers {Size Digest} Digest Tag Logo Title Documentation DownloadCount Source Description Licenses History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}}}}}}`,
detailedImageInfo: (name, tag) =>
`/v2/_zot/ext/search?query={Image(image: "${name}:${tag}"){RepoName Tag Digest LastUpdated Size ConfigDigest Platform {Os Arch} Vendor Licenses Logo}}`,
`/v2/_zot/ext/search?query={Image(image: "${name}:${tag}"){RepoName IsSigned Vulnerabilities {MaxSeverity Count} Tag Digest LastUpdated Size ConfigDigest Platform {Os Arch} Vendor Licenses Logo}}`,
vulnerabilitiesForRepo: (name) =>
`/v2/_zot/ext/search?query={CVEListForImage(image: "${name}"){Tag, CVEList {Id Title Description Severity PackageList {Name InstalledVersion FixedVersion}}}}`,
layersDetailsForImage: (name) =>
@ -75,9 +75,9 @@ const endpoints = {
imageListWithCVEFixed: (cveId, repoName) =>
`/v2/_zot/ext/search?query={ImageListWithCVEFixed(id:"${cveId}", image:"${repoName}") {Tag}}`,
dependsOnForImage: (name) =>
`/v2/_zot/ext/search?query={BaseImageList(image: "${name}"){RepoName Tag Description Digest Vendor DownloadCount LastUpdated Size Platform {Os Arch} IsSigned}}`,
`/v2/_zot/ext/search?query={BaseImageList(image: "${name}"){RepoName Tag Description Digest Vendor DownloadCount LastUpdated Size Platform {Os Arch} IsSigned Vulnerabilities {MaxSeverity Count}}}`,
isDependentOnForImage: (name) =>
`/v2/_zot/ext/search?query={DerivedImageList(image: "${name}"){RepoName Tag Description Digest Vendor DownloadCount LastUpdated Size Platform {Os Arch} IsSigned}}`,
`/v2/_zot/ext/search?query={DerivedImageList(image: "${name}"){RepoName Tag Description Digest Vendor DownloadCount LastUpdated Size Platform {Os Arch} IsSigned Vulnerabilities {MaxSeverity Count}}}`,
globalSearch: ({ searchQuery = '""', pageNumber = 1, pageSize = 15, filter = {} }) => {
const searchParam = searchQuery !== '' ? `query:"${searchQuery}"` : `query:""`;
const paginationParam = `requestedPage: {limit:${pageSize} offset:${(pageNumber - 1) * pageSize}}`;
@ -87,7 +87,7 @@ const endpoints = {
if (filter.HasToBeSigned) filterParam += ` HasToBeSigned: ${filter.HasToBeSigned}`;
filterParam += '}';
if (Object.keys(filter).length === 0) filterParam = '';
return `/v2/_zot/ext/search?query={GlobalSearch(${searchParam}, ${paginationParam} ${filterParam}) {Repos {Name LastUpdated Size Platforms { Os Arch } NewestImage { Tag Description IsSigned Logo Licenses Vendor Labels } DownloadCount}}}`;
return `/v2/_zot/ext/search?query={GlobalSearch(${searchParam}, ${paginationParam} ${filterParam}) {Repos {Name LastUpdated Size Platforms { Os Arch } NewestImage { Tag Vulnerabilities {MaxSeverity Count} Description IsSigned Logo Licenses Vendor Labels } DownloadCount}}}`;
},
imageSuggestions: ({ searchQuery = '""', pageNumber = 1, pageSize = 15 }) => {
const searchParam = searchQuery !== '' ? `query:"${searchQuery}"` : `query:""`;

View File

@ -78,8 +78,8 @@ function DependsOn(props) {
.get(`${host()}${endpoints.dependsOnForImage(name)}`, abortController.signal)
.then((response) => {
if (response.data && response.data.data) {
let images = response.data.data.BaseImageList;
setImages(images);
let imagesData = response.data.data.BaseImageList;
setImages(imagesData);
}
setIsLoading(false);
})
@ -105,6 +105,7 @@ function DependsOn(props) {
size={dependence.Size}
digest={dependence.Digest}
key={index}
vulnerabiltySeverity={dependence.Vulnerabilities?.MaxSeverity}
lastUpdated={dependence.LastUpdated}
/>
);

View File

@ -113,6 +113,8 @@ function Explore() {
vendor={item.vendor}
platforms={item.platforms}
key={index}
vulnerabiltySeverity={item.vulnerabiltySeverity}
vulnerabilityCount={item.vulnerabilityCount}
lastUpdated={item.lastUpdated}
logo={item.logo}
/>

View File

@ -96,7 +96,14 @@ function Home() {
homeData.slice(0, 4).map((item, index) => {
return (
<Grid item xs={3} key={index}>
<PreviewCard name={item.name} lastUpdated={item.lastUpdated} isSigned={item.isSigned} logo={item.logo} />
<PreviewCard
name={item.name}
lastUpdated={item.lastUpdated}
isSigned={item.isSigned}
vulnerabiltySeverity={item.vulnerabiltySeverity}
vulnerabilityCount={item.vulnerabilityCount}
logo={item.logo}
/>
</Grid>
);
})
@ -140,6 +147,8 @@ function Home() {
vendor={item.vendor}
platforms={item.platforms}
key={index}
vulnerabiltySeverity={item.vulnerabiltySeverity}
vulnerabilityCount={item.vulnerabilityCount}
lastUpdated={item.lastUpdated}
logo={item.logo}
/>

View File

@ -78,8 +78,8 @@ function IsDependentOn(props) {
.get(`${host()}${endpoints.isDependentOnForImage(name)}`, abortController.signal)
.then((response) => {
if (response.data && response.data.data) {
let images = response.data.data.DerivedImageList;
setImages(images);
let imageData = response.data.data.DerivedImageList;
setImages(imageData);
}
setIsLoading(false);
})
@ -105,6 +105,7 @@ function IsDependentOn(props) {
size={dependence.Size}
digest={dependence.Digest}
key={index}
vulnerabiltySeverity={dependence.Vulnerabilities?.MaxSeverity}
lastUpdated={dependence.LastUpdated}
/>
);

View File

@ -12,6 +12,8 @@ import repocube4 from '../assets/repocube-4.png';
//icons
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
import PestControlOutlinedIcon from '@mui/icons-material/PestControlOutlined';
import PestControlIcon from '@mui/icons-material/PestControl';
import { isEmpty } from 'lodash';
//import GppMaybeOutlinedIcon from '@mui/icons-material/GppMaybeOutlined';
@ -67,31 +69,118 @@ const useStyles = makeStyles(() => ({
}
}));
//function that returns a random element from an array
// function getRandom (list) {
// return list[Math.floor((Math.random()*list.length))];
// }
function PreviewCard(props) {
const classes = useStyles();
const navigate = useNavigate();
const { name, isSigned, logo } = props;
const { name, isSigned, vulnerabiltySeverity, vulnerabilityCount, logo } = props;
const goToDetails = () => {
navigate(`/image/${encodeURIComponent(name)}`);
};
// const vulnerabilityCheck = () => {
// const noneVulnerability = <PestControlOutlinedIcon sx={{ color: "#43A047!important", padding:"0.2rem", background: "#E8F5E9", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
// const unknownVulnerability = <PestControlOutlinedIcon sx={{ color: "#52637A!important", padding:"0.2rem", background: "#ECEFF1", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
// const lowVulnerability = <PestControlOutlinedIcon sx={{ color: "#FB8C00!important", padding:"0.2rem", background: "#FFF3E0", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
// const mediumVulnerability = <PestControlIcon sx={{ color: "#FB8C00!important", padding:"0.2rem", background: "#FFF3E0", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
// const highVulnerability = <PestControlOutlinedIcon sx={{ color: "#E53935!important", padding:"0.2rem", background: "#FEEBEE", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
// const criticalVulnerability = <PestControlIcon sx={{ color: "#E53935!important", padding:"0.2rem", background: "#FEEBEE", borderRadius: "1rem", height:"1.5rem", width:"1.6rem" }} />;
const vulnerabilityCheck = () => {
const noneVulnerability = (
<PestControlOutlinedIcon
sx={{
color: '#43A047!important',
padding: '0.2rem',
background: '#E8F5E9',
borderRadius: '1rem',
height: '1.5rem',
width: '1.6rem'
}}
data-testid="none-vulnerability-icon"
/>
);
const unknownVulnerability = (
<PestControlOutlinedIcon
sx={{
color: '#52637A!important',
padding: '0.2rem',
background: '#ECEFF1',
borderRadius: '1rem',
height: '1.5rem',
width: '1.6rem'
}}
data-testid="unknown-vulnerability-icon"
/>
);
const lowVulnerability = (
<PestControlOutlinedIcon
sx={{
color: '#FB8C00!important',
padding: '0.2rem',
background: '#FFF3E0',
borderRadius: '1rem',
height: '1.5rem',
width: '1.6rem'
}}
data-testid="low-vulnerability-icon"
/>
);
const mediumVulnerability = (
<PestControlIcon
sx={{
color: '#FB8C00!important',
padding: '0.2rem',
background: '#FFF3E0',
borderRadius: '1rem',
height: '1.5rem',
width: '1.6rem'
}}
data-testid="medium-vulnerability-icon"
/>
);
const highVulnerability = (
<PestControlOutlinedIcon
sx={{
color: '#E53935!important',
padding: '0.2rem',
background: '#FEEBEE',
borderRadius: '1rem',
height: '1.5rem',
width: '1.6rem'
}}
data-testid="high-vulnerability-icon"
/>
);
const criticalVulnerability = (
<PestControlIcon
sx={{
color: '#E53935!important',
padding: '0.2rem',
background: '#FEEBEE',
borderRadius: '1rem',
height: '1.5rem',
width: '1.6rem'
}}
data-testid="critical-vulnerability-icon"
/>
);
// const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability]
// return(getRandom(arrVulnerability));
// }
let result;
switch (vulnerabiltySeverity) {
case 'NONE':
result = noneVulnerability;
break;
case 'LOW':
result = lowVulnerability;
break;
case 'MEDIUM':
result = mediumVulnerability;
break;
case 'HIGH':
result = highVulnerability;
break;
case 'CRITICAL':
result = criticalVulnerability;
break;
default:
result = unknownVulnerability;
}
return result;
};
const signatureCheck = () => {
const unverifiedSignature = (
@ -134,7 +223,7 @@ function PreviewCard(props) {
<CardContent className={classes.content}>
<Grid container spacing={1}>
<Grid container item xs={12}>
<Stack direction="row" spacing={3} sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
<Stack direction="row" spacing={4} sx={{ display: 'flex', alignItems: 'left', flexWrap: 'wrap' }}>
<CardMedia
classes={{
root: classes.media,
@ -152,7 +241,7 @@ function PreviewCard(props) {
size: '1.5rem',
lineHeight: '2rem',
color: '#220052',
width: '8rem',
width: '5rem',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis'
@ -161,8 +250,12 @@ function PreviewCard(props) {
{name}
</Typography>
</Tooltip>
{/* {vulnerabilityCheck()} */}
{signatureCheck()}
<Stack direction="row" spacing={0.5} sx={{ marginLeft: 'auto', marginRight: 0 }}>
<Tooltip title={!isNaN(vulnerabilityCount) ? vulnerabilityCount : ''} placement="top">
{vulnerabilityCheck()}
</Tooltip>
{signatureCheck()}
</Stack>
</Stack>
</Grid>
<Grid item xs={12} mt={2}></Grid>

View File

@ -18,6 +18,8 @@ import repocube4 from '../assets/repocube-4.png';
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
import { Markdown } from 'utilities/MarkdowntojsxWrapper';
import PestControlOutlinedIcon from '@mui/icons-material/PestControlOutlined';
import PestControlIcon from '@mui/icons-material/PestControl';
import { isEmpty } from 'lodash';
// temporary utility to get image
@ -92,23 +94,120 @@ const useStyles = makeStyles(() => ({
function RepoCard(props) {
const classes = useStyles();
const navigate = useNavigate();
const { name, vendor, platforms, description, downloads, isSigned, lastUpdated, version, logo } = props;
const {
name,
vendor,
platforms,
description,
downloads,
isSigned,
lastUpdated,
logo,
version,
vulnerabiltySeverity,
vulnerabilityCount
} = props;
const goToDetails = () => {
navigate(`/image/${encodeURIComponent(name)}`);
};
// const vulnerabilityCheck = () => {
// const noneVulnerability = <Chip label="None Vulnerability" sx={{backgroundColor: "#E8F5E9",color: "#388E3C",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#388E3C!important" }} />}/>;
// const unknownVulnerability = <Chip label="Unknown Vulnerability" sx={{backgroundColor: "#ECEFF1",color: "#52637A",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#52637A!important" }} />}/>;
// const lowVulnerability = <Chip label="Low Vulnerability" sx={{backgroundColor: "#FFF3E0",color: "#FB8C00",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#FB8C00!important" }} />}/>;
// const mediumVulnerability = <Chip label="Medium Vulnerability" sx={{backgroundColor: "#FFF3E0",color: "#FB8C00",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlIcon sx={{ color: "#FB8C00!important" }} />}/>;
// const highVulnerability = <Chip label="High Vulnerability" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
// const criticalVulnerability = <Chip label="Critical Vulnerability" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <PestControlIcon sx={{ color: "#E53935!important" }} />}/>;
const vulnerabilityCheck = () => {
const noneVulnerability = (
<Chip
label="None Vulnerability"
sx={{ backgroundColor: '#E8F5E9', color: '#388E3C', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#388E3C!important' }} />}
data-testid="none-vulnerability-chip"
/>
);
const unknownVulnerability = (
<Chip
label="Unknown Vulnerability"
sx={{ backgroundColor: '#ECEFF1', color: '#52637A', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#52637A!important' }} />}
data-testid="unknown-vulnerability-chip"
/>
);
const lowVulnerability = (
<Chip
label="Low Vulnerability"
sx={{ backgroundColor: '#FFF3E0', color: '#FB8C00', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#FB8C00!important' }} />}
data-testid="low-vulnerability-chip"
/>
);
const mediumVulnerability = (
<Chip
label="Medium Vulnerability"
sx={{ backgroundColor: '#FFF3E0', color: '#FB8C00', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlIcon sx={{ color: '#FB8C00!important' }} />}
data-testid="medium-vulnerability-chip"
/>
);
const highVulnerability = (
<Chip
label="High Vulnerability"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#E53935!important' }} />}
data-testid="high-vulnerability-chip"
/>
);
const criticalVulnerability = (
<Chip
label="Critical Vulnerability"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlIcon sx={{ color: '#E53935!important' }} />}
data-testid="critical-vulnerability-chip"
/>
);
let result;
switch (vulnerabiltySeverity) {
case 'NONE':
result = noneVulnerability;
break;
case 'LOW':
result = lowVulnerability;
break;
case 'MEDIUM':
result = mediumVulnerability;
break;
case 'HIGH':
result = highVulnerability;
break;
case 'CRITICAL':
result = criticalVulnerability;
break;
default:
result = unknownVulnerability;
}
// const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability]
// return(getRandom(arrVulnerability));
// };
return result;
};
const signatureCheck = () => {
const unverifiedSignature = (
@ -202,7 +301,9 @@ function RepoCard(props) {
{name}
</Typography>
</Tooltip>
{/* {vulnerabilityCheck()} */}
<Tooltip title={!isNaN(vulnerabilityCount) ? vulnerabilityCount : ''} placement="top">
{vulnerabilityCheck()}
</Tooltip>
{signatureCheck()}
{/* <Chip label="Verified licensee" sx={{ backgroundColor: "#E8F5E9", color: "#388E3C" }} variant="filled" onDelete={() => { return }} deleteIcon={vulnerabilityCheck()} /> */}
</Stack>

View File

@ -7,7 +7,7 @@ import { api, endpoints } from '../api';
// components
import Tags from './Tags.jsx';
import { Box, Card, CardContent, CardMedia, Chip, Grid, Stack, Tab, Typography } from '@mui/material';
import { Box, Card, CardContent, CardMedia, Chip, Grid, Stack, Tab, Tooltip, Typography } from '@mui/material';
import makeStyles from '@mui/styles/makeStyles';
import { host } from '../host';
@ -17,6 +17,12 @@ import repocube2 from '../assets/repocube-2.png';
import repocube3 from '../assets/repocube-3.png';
import repocube4 from '../assets/repocube-4.png';
import { TabContext, TabList, TabPanel } from '@mui/lab';
//icons
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
import PestControlOutlinedIcon from '@mui/icons-material/PestControlOutlined';
import PestControlIcon from '@mui/icons-material/PestControl';
import RepoDetailsMetadata from './RepoDetailsMetadata';
import Loading from './Loading';
import { isEmpty } from 'lodash';
@ -149,6 +155,9 @@ function RepoDetails() {
downloads: repoInfo.Summary?.NewestImage?.DownloadCount,
overview: repoInfo.Summary?.NewestImage?.Documentation,
license: repoInfo.Summary?.NewestImage?.Licenses,
vulnerabiltySeverity: repoInfo.Summary?.NewestImage?.Vulnerabilities?.MaxSeverity,
vulnerabilityCount: repoInfo.Summary?.NewestImage?.Vulnerabilities?.Count,
isSigned: repoInfo.Summary?.NewestImage?.IsSigned,
logo: repoInfo.Summary?.NewestImage?.Logo
};
setRepoDetailData(imageData);
@ -167,6 +176,135 @@ function RepoDetails() {
};
}, [name]);
const signatureCheck = () => {
const unverifiedSignature = (
<Chip
label="Unverified Signature"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<GppBadOutlinedIcon sx={{ color: '#E53935!important' }} />}
/>
);
const verifiedSignature = (
<Chip
label="Verified Signature"
sx={{ backgroundColor: '#E8F5E9', color: '#388E3C', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<GppGoodOutlinedIcon sx={{ color: '#388E3C!important' }} />}
/>
);
// @ts-ignore
if (repoDetailData.isSigned) {
return verifiedSignature;
} else {
return unverifiedSignature;
}
};
const vulnerabilityCheck = () => {
const noneVulnerability = (
<Chip
label="None Vulnerability"
sx={{ backgroundColor: '#E8F5E9', color: '#388E3C', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#388E3C!important' }} />}
data-testid="none-vulnerability-chip"
/>
);
const unknownVulnerability = (
<Chip
label="Unknown Vulnerability"
sx={{ backgroundColor: '#ECEFF1', color: '#52637A', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#52637A!important' }} />}
data-testid="unknown-vulnerability-chip"
/>
);
const lowVulnerability = (
<Chip
label="Low Vulnerability"
sx={{ backgroundColor: '#FFF3E0', color: '#FB8C00', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#FB8C00!important' }} />}
data-testid="low-vulnerability-chip"
/>
);
const mediumVulnerability = (
<Chip
label="Medium Vulnerability"
sx={{ backgroundColor: '#FFF3E0', color: '#FB8C00', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlIcon sx={{ color: '#FB8C00!important' }} />}
data-testid="medium-vulnerability-chip"
/>
);
const highVulnerability = (
<Chip
label="High Vulnerability"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#E53935!important' }} />}
data-testid="high-vulnerability-chip"
/>
);
const criticalVulnerability = (
<Chip
label="Critical Vulnerability"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlIcon sx={{ color: '#E53935!important' }} />}
data-testid="critical-vulnerability-chip"
/>
);
let result;
// @ts-ignore
switch (repoDetailData.vulnerabiltySeverity) {
case 'NONE':
result = noneVulnerability;
break;
case 'LOW':
result = lowVulnerability;
break;
case 'MEDIUM':
result = mediumVulnerability;
break;
case 'HIGH':
result = highVulnerability;
break;
case 'CRITICAL':
result = criticalVulnerability;
break;
default:
result = unknownVulnerability;
}
return result;
};
const platformChips = () => {
// @ts-ignore
const platforms = repoDetailData?.platforms || [];
@ -195,6 +333,7 @@ function RepoDetails() {
));
};
// @ts-ignore
// @ts-ignore
const handleTabChange = (event, newValue) => {
setSelectedTab(newValue);
@ -249,8 +388,16 @@ function RepoDetails() {
<Typography variant="h3" className={classes.repoName}>
{name}
</Typography>
{/* {vulnerabilityCheck()}
{signatureCheck()} */}
<Tooltip
title={
// @ts-ignore
!isNaN(repoDetailData.vulnerabilityCount) ? repoDetailData.vulnerabilityCount : ''
}
placement="top"
>
{vulnerabilityCheck()}
</Tooltip>
{signatureCheck()}
{/* <BookmarkIcon sx={{color:"#52637A"}}/> */}
</Stack>
<Typography

View File

@ -1,3 +1,4 @@
// @ts-nocheck
// react global
import { useParams } from 'react-router-dom';
import React, { useEffect, useMemo, useState } from 'react';
@ -11,6 +12,7 @@ import {
Card,
CardContent,
CardMedia,
Chip,
Grid,
FormControl,
IconButton,
@ -18,12 +20,19 @@ import {
Select,
MenuItem,
Tab,
Tooltip,
Typography
} from '@mui/material';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import makeStyles from '@mui/styles/makeStyles';
import { host, hostRoot } from '../host';
//icons
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
import PestControlOutlinedIcon from '@mui/icons-material/PestControlOutlined';
import PestControlIcon from '@mui/icons-material/PestControl';
// placeholder images
import repocube1 from '../assets/repocube-1.png';
import repocube2 from '../assets/repocube-2.png';
@ -166,6 +175,9 @@ function TagDetails() {
vendor: imageInfo.Vendor,
history: imageInfo.History,
license: imageInfo.Licenses,
vulnerabiltySeverity: imageInfo.Vulnerabilities?.MaxSeverity,
vulnerabilityCount: imageInfo.Vulnerabilities?.Count,
isSigned: imageInfo.IsSigned,
logo: imageInfo.Logo
};
setImageDetailData(imageData);
@ -182,14 +194,134 @@ function TagDetails() {
};
}, [name, tag]);
// const signatureCheck = () => {
// const unverifiedSignature = <Chip label="Unverified Signature" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppBadOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
// const untrustedSignature = <Chip label="Untrusted Signature" sx={{backgroundColor: "#ECEFF1",color: "#52637A",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppMaybeOutlinedIcon sx={{ color: "#52637A!important" }} />}/>;
// const verifiedSignature = <Chip label="Verified Signature" sx={{backgroundColor: "#E8F5E9",color: "#388E3C",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppGoodOutlinedIcon sx={{ color: "#388E3C!important" }} />}/>;
const signatureCheck = () => {
const unverifiedSignature = (
<Chip
label="Unverified Signature"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<GppBadOutlinedIcon sx={{ color: '#E53935!important' }} />}
/>
);
const verifiedSignature = (
<Chip
label="Verified Signature"
sx={{ backgroundColor: '#E8F5E9', color: '#388E3C', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<GppGoodOutlinedIcon sx={{ color: '#388E3C!important' }} />}
/>
);
// @ts-ignore
if (imageDetailData.isSigned) {
return verifiedSignature;
} else {
return unverifiedSignature;
}
};
// const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature]
// return(getRandom(arrSignature));
// }
const vulnerabilityCheck = () => {
const noneVulnerability = (
<Chip
label="None Vulnerability"
sx={{ backgroundColor: '#E8F5E9', color: '#388E3C', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#388E3C!important' }} />}
data-testid="none-vulnerability-chip"
/>
);
const unknownVulnerability = (
<Chip
label="Unknown Vulnerability"
sx={{ backgroundColor: '#ECEFF1', color: '#52637A', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#52637A!important' }} />}
data-testid="unknown-vulnerability-chip"
/>
);
const lowVulnerability = (
<Chip
label="Low Vulnerability"
sx={{ backgroundColor: '#FFF3E0', color: '#FB8C00', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#FB8C00!important' }} />}
data-testid="low-vulnerability-chip"
/>
);
const mediumVulnerability = (
<Chip
label="Medium Vulnerability"
sx={{ backgroundColor: '#FFF3E0', color: '#FB8C00', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlIcon sx={{ color: '#FB8C00!important' }} />}
data-testid="medium-vulnerability-chip"
/>
);
const highVulnerability = (
<Chip
label="High Vulnerability"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlOutlinedIcon sx={{ color: '#E53935!important' }} />}
data-testid="high-vulnerability-chip"
/>
);
const criticalVulnerability = (
<Chip
label="Critical Vulnerability"
sx={{ backgroundColor: '#FEEBEE', color: '#E53935', fontSize: '0.8125rem' }}
variant="filled"
onDelete={() => {
return;
}}
deleteIcon={<PestControlIcon sx={{ color: '#E53935!important' }} />}
data-testid="critical-vulnerability-chip"
/>
);
let result;
// @ts-ignore
switch (imageDetailData.vulnerabiltySeverity) {
case 'NONE':
result = noneVulnerability;
break;
case 'LOW':
result = lowVulnerability;
break;
case 'MEDIUM':
result = mediumVulnerability;
break;
case 'HIGH':
result = highVulnerability;
break;
case 'CRITICAL':
result = criticalVulnerability;
break;
default:
result = unknownVulnerability;
}
return result;
};
const getPlatform = () => {
// @ts-ignore
@ -225,15 +357,25 @@ function TagDetails() {
image={
// @ts-ignore
// eslint-disable-next-line prettier/prettier
!isEmpty(imageDetailData?.logo) ? `data:image/ png;base64, ${imageDetailData?.logo}` : randomImage()
!isEmpty(imageDetailData?.logo)
? `data:image/ png;base64, ${imageDetailData?.logo}`
: randomImage()
}
alt="icon"
/>
<Typography variant="h3" className={classes.repoName}>
{name}:{tag}
</Typography>
{/* {vulnerabilityCheck()}
{signatureCheck()} */}
<Tooltip
title={
// @ts-ignore
!isNaN(imageDetailData.vulnerabilityCount) ? imageDetailData.vulnerabilityCount : ''
}
placement="top"
>
{vulnerabilityCheck()}
</Tooltip>
{signatureCheck()}
{/* <BookmarkIcon sx={{color:"#52637A"}}/> */}
</Stack>
<Typography

View File

@ -11,7 +11,9 @@ const mapToRepo = (responseRepo) => {
vendor: responseRepo.NewestImage?.Vendor,
logo: responseRepo.NewestImage?.Logo,
lastUpdated: responseRepo.LastUpdated,
downloads: responseRepo.DownloadCount
downloads: responseRepo.DownloadCount,
vulnerabiltySeverity: responseRepo.NewestImage?.Vulnerabilities?.MaxSeverity,
vulnerabilityCount: responseRepo.NewestImage?.Vulnerabilities?.Count
};
};