@backstage-community/plugin-quay 1.14.2

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +670 -0
  2. package/README.md +102 -0
  3. package/app-config.dynamic.yaml +12 -0
  4. package/config.d.ts +30 -0
  5. package/dist/api/index.esm.js +77 -0
  6. package/dist/api/index.esm.js.map +1 -0
  7. package/dist/components/PermissionAlert/PermissionAlert.esm.js +9 -0
  8. package/dist/components/PermissionAlert/PermissionAlert.esm.js.map +1 -0
  9. package/dist/components/QuayRepository/QuayRepository.esm.js +42 -0
  10. package/dist/components/QuayRepository/QuayRepository.esm.js.map +1 -0
  11. package/dist/components/QuayRepository/tableHeading.esm.js +74 -0
  12. package/dist/components/QuayRepository/tableHeading.esm.js.map +1 -0
  13. package/dist/components/QuayTagDetails/component.esm.js +107 -0
  14. package/dist/components/QuayTagDetails/component.esm.js.map +1 -0
  15. package/dist/components/QuayTagPage/component.esm.js +40 -0
  16. package/dist/components/QuayTagPage/component.esm.js.map +1 -0
  17. package/dist/components/Router.esm.js +12 -0
  18. package/dist/components/Router.esm.js.map +1 -0
  19. package/dist/hooks/quay.esm.js +113 -0
  20. package/dist/hooks/quay.esm.js.map +1 -0
  21. package/dist/hooks/useQuayViewPermission.esm.js +12 -0
  22. package/dist/hooks/useQuayViewPermission.esm.js.map +1 -0
  23. package/dist/index.d.ts +27 -0
  24. package/dist/index.esm.js +3 -0
  25. package/dist/index.esm.js.map +1 -0
  26. package/dist/lib/utils.esm.js +90 -0
  27. package/dist/lib/utils.esm.js.map +1 -0
  28. package/dist/plugin.esm.js +33 -0
  29. package/dist/plugin.esm.js.map +1 -0
  30. package/dist/routes.esm.js +13 -0
  31. package/dist/routes.esm.js.map +1 -0
  32. package/dist/types.esm.js +22 -0
  33. package/dist/types.esm.js.map +1 -0
  34. package/package.json +106 -0
@@ -0,0 +1,113 @@
1
+ import React, { useMemo } from 'react';
2
+ import { useAsync } from 'react-use';
3
+ import { useApi } from '@backstage/core-plugin-api';
4
+ import { useEntity } from '@backstage/plugin-catalog-react';
5
+ import { formatDate, formatByteSize } from '@janus-idp/shared-react';
6
+ import { makeStyles, Box, Chip } from '@material-ui/core';
7
+ import { quayApiRef } from '../api/index.esm.js';
8
+
9
+ const useLocalStyles = makeStyles({
10
+ chip: {
11
+ margin: 0,
12
+ marginRight: ".2em",
13
+ height: "1.5em",
14
+ "& > span": {
15
+ padding: ".3em"
16
+ }
17
+ }
18
+ });
19
+ const useTags = (organization, repository) => {
20
+ const quayClient = useApi(quayApiRef);
21
+ const [tags, setTags] = React.useState([]);
22
+ const [tagManifestLayers, setTagManifestLayers] = React.useState({});
23
+ const [tagManifestStatuses, setTagManifestStatuses] = React.useState({});
24
+ const localClasses = useLocalStyles();
25
+ const fetchSecurityDetails = async (tag) => {
26
+ const securityDetails = await quayClient.getSecurityDetails(
27
+ organization,
28
+ repository,
29
+ tag.manifest_digest
30
+ );
31
+ return securityDetails;
32
+ };
33
+ const { loading } = useAsync(async () => {
34
+ const tagsResponse = await quayClient.getTags(organization, repository);
35
+ Promise.all(
36
+ tagsResponse.tags.map(async (tag) => {
37
+ const securityDetails = await fetchSecurityDetails(tag);
38
+ const securityData = securityDetails.data;
39
+ const securityStatus = securityDetails.status;
40
+ setTagManifestStatuses((prevState) => ({
41
+ ...prevState,
42
+ [tag.manifest_digest]: securityStatus
43
+ }));
44
+ if (securityData) {
45
+ setTagManifestLayers((prevState) => ({
46
+ ...prevState,
47
+ [tag.manifest_digest]: securityData.Layer
48
+ }));
49
+ }
50
+ })
51
+ );
52
+ setTags((prevTags) => [...prevTags, ...tagsResponse.tags]);
53
+ return tagsResponse;
54
+ });
55
+ const data = useMemo(() => {
56
+ return Object.values(tags)?.map((tag) => {
57
+ const hashFunc = tag.manifest_digest.substring(0, 6);
58
+ const shortHash = tag.manifest_digest.substring(7, 19);
59
+ return {
60
+ id: `${tag.manifest_digest}-${tag.name}`,
61
+ name: tag.name,
62
+ last_modified: formatDate(tag.last_modified),
63
+ size: formatByteSize(tag.size),
64
+ rawSize: tag.size,
65
+ manifest_digest: /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Chip, { label: hashFunc, className: localClasses.chip }), shortHash),
66
+ expiration: tag.expiration,
67
+ securityDetails: tagManifestLayers[tag.manifest_digest],
68
+ securityStatus: tagManifestStatuses[tag.manifest_digest],
69
+ manifest_digest_raw: tag.manifest_digest
70
+ // is_manifest_list: tag.is_manifest_list,
71
+ // reversion: tag.reversion,
72
+ // start_ts: tag.start_ts,
73
+ // end_ts: tag.end_ts,
74
+ // manifest_list: tag.manifest_list,
75
+ };
76
+ });
77
+ }, [tags, localClasses.chip, tagManifestLayers, tagManifestStatuses]);
78
+ return { loading, data };
79
+ };
80
+ const QUAY_ANNOTATION_REPOSITORY = "quay.io/repository-slug";
81
+ const useQuayAppData = ({ entity }) => {
82
+ const repositorySlug = entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY] ?? "";
83
+ if (!repositorySlug) {
84
+ throw new Error("'Quay' annotations are missing");
85
+ }
86
+ return { repositorySlug };
87
+ };
88
+ const useRepository = () => {
89
+ const { entity } = useEntity();
90
+ const { repositorySlug } = useQuayAppData({ entity });
91
+ const info = repositorySlug.split("/");
92
+ const organization = info.shift();
93
+ const repository = info.join("/");
94
+ return {
95
+ organization,
96
+ repository
97
+ };
98
+ };
99
+ const useTagDetails = (org, repo, digest) => {
100
+ const quayClient = useApi(quayApiRef);
101
+ const result = useAsync(async () => {
102
+ const manifestLayer = await quayClient.getSecurityDetails(
103
+ org,
104
+ repo,
105
+ digest
106
+ );
107
+ return manifestLayer;
108
+ });
109
+ return result;
110
+ };
111
+
112
+ export { QUAY_ANNOTATION_REPOSITORY, useQuayAppData, useRepository, useTagDetails, useTags };
113
+ //# sourceMappingURL=quay.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quay.esm.js","sources":["../../src/hooks/quay.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useMemo } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { Entity } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useEntity } from '@backstage/plugin-catalog-react';\n\nimport { formatByteSize, formatDate } from '@janus-idp/shared-react';\nimport { Box, Chip, makeStyles } from '@material-ui/core';\n\nimport { quayApiRef } from '../api';\nimport { Layer, QuayTagData, Tag } from '../types';\n\nconst useLocalStyles = makeStyles({\n chip: {\n margin: 0,\n marginRight: '.2em',\n height: '1.5em',\n '& > span': {\n padding: '.3em',\n },\n },\n});\n\nexport const useTags = (organization: string, repository: string) => {\n const quayClient = useApi(quayApiRef);\n const [tags, setTags] = React.useState<Tag[]>([]);\n const [tagManifestLayers, setTagManifestLayers] = React.useState<\n Record<string, Layer>\n >({});\n const [tagManifestStatuses, setTagManifestStatuses] = React.useState<\n Record<string, string>\n >({});\n const localClasses = useLocalStyles();\n\n const fetchSecurityDetails = async (tag: Tag) => {\n const securityDetails = await quayClient.getSecurityDetails(\n organization,\n repository,\n tag.manifest_digest,\n );\n return securityDetails;\n };\n\n const { loading } = useAsync(async () => {\n const tagsResponse = await quayClient.getTags(organization, repository);\n Promise.all(\n tagsResponse.tags.map(async tag => {\n const securityDetails = await fetchSecurityDetails(tag);\n const securityData = securityDetails.data;\n const securityStatus = securityDetails.status;\n\n setTagManifestStatuses(prevState => ({\n ...prevState,\n [tag.manifest_digest]: securityStatus,\n }));\n\n if (securityData) {\n setTagManifestLayers(prevState => ({\n ...prevState,\n [tag.manifest_digest]: securityData.Layer,\n }));\n }\n }),\n );\n setTags(prevTags => [...prevTags, ...tagsResponse.tags]);\n return tagsResponse;\n });\n\n const data: QuayTagData[] = useMemo(() => {\n return Object.values(tags)?.map(tag => {\n const hashFunc = tag.manifest_digest.substring(0, 6);\n const shortHash = tag.manifest_digest.substring(7, 19);\n return {\n id: `${tag.manifest_digest}-${tag.name}`,\n name: tag.name,\n last_modified: formatDate(tag.last_modified),\n size: formatByteSize(tag.size),\n rawSize: tag.size,\n manifest_digest: (\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Chip label={hashFunc} className={localClasses.chip} />\n {shortHash}\n </Box>\n ),\n expiration: tag.expiration,\n securityDetails: tagManifestLayers[tag.manifest_digest],\n securityStatus: tagManifestStatuses[tag.manifest_digest],\n manifest_digest_raw: tag.manifest_digest,\n // is_manifest_list: tag.is_manifest_list,\n // reversion: tag.reversion,\n // start_ts: tag.start_ts,\n // end_ts: tag.end_ts,\n // manifest_list: tag.manifest_list,\n };\n });\n }, [tags, localClasses.chip, tagManifestLayers, tagManifestStatuses]);\n\n return { loading, data };\n};\n\nexport const QUAY_ANNOTATION_REPOSITORY = 'quay.io/repository-slug';\n\nexport const useQuayAppData = ({ entity }: { entity: Entity }) => {\n const repositorySlug =\n entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY] ?? '';\n\n if (!repositorySlug) {\n throw new Error(\"'Quay' annotations are missing\");\n }\n return { repositorySlug };\n};\n\nexport const useRepository = () => {\n const { entity } = useEntity();\n const { repositorySlug } = useQuayAppData({ entity });\n const info = repositorySlug.split('/');\n\n const organization = info.shift() as 'string';\n const repository = info.join('/');\n return {\n organization,\n repository,\n };\n};\n\nexport const useTagDetails = (org: string, repo: string, digest: string) => {\n const quayClient = useApi(quayApiRef);\n const result = useAsync(async () => {\n const manifestLayer = await quayClient.getSecurityDetails(\n org,\n repo,\n digest,\n );\n return manifestLayer;\n });\n return result;\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { usePermission } from '@backstage/plugin-permission-react';
2
+ import { quayViewPermission } from '@backstage-community/plugin-quay-common';
3
+
4
+ const useQuayViewPermission = () => {
5
+ const quayViewPermissionResult = usePermission({
6
+ permission: quayViewPermission
7
+ });
8
+ return quayViewPermissionResult.allowed;
9
+ };
10
+
11
+ export { useQuayViewPermission };
12
+ //# sourceMappingURL=useQuayViewPermission.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useQuayViewPermission.esm.js","sources":["../../src/hooks/useQuayViewPermission.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { usePermission } from '@backstage/plugin-permission-react';\n\nimport { quayViewPermission } from '@backstage-community/plugin-quay-common';\n\nexport const useQuayViewPermission = () => {\n const quayViewPermissionResult = usePermission({\n permission: quayViewPermission,\n });\n\n return quayViewPermissionResult.allowed;\n};\n"],"names":[],"mappings":";;;AAmBO,MAAM,wBAAwB,MAAM;AACzC,EAAA,MAAM,2BAA2B,aAAc,CAAA;AAAA,IAC7C,UAAY,EAAA,kBAAA;AAAA,GACb,CAAA,CAAA;AAED,EAAA,OAAO,wBAAyB,CAAA,OAAA,CAAA;AAClC;;;;"}
@@ -0,0 +1,27 @@
1
+ /// <reference types="react" />
2
+ import * as react from 'react';
3
+ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
4
+ import { Entity } from '@backstage/catalog-model';
5
+
6
+ /**
7
+ * Quay plugin
8
+ *
9
+ * @public
10
+ */
11
+ declare const quayPlugin: _backstage_core_plugin_api.BackstagePlugin<{
12
+ root: _backstage_core_plugin_api.RouteRef<undefined>;
13
+ tag: _backstage_core_plugin_api.SubRouteRef<_backstage_core_plugin_api.PathParams<"/tag/:digest">>;
14
+ }, {}, {}>;
15
+ /**
16
+ * Quay page
17
+ *
18
+ * @public
19
+ */
20
+ declare const QuayPage: () => react.JSX.Element;
21
+
22
+ /** *
23
+ * @public
24
+ */
25
+ declare const isQuayAvailable: (entity: Entity) => boolean;
26
+
27
+ export { QuayPage, isQuayAvailable, quayPlugin };
@@ -0,0 +1,3 @@
1
+ export { QuayPage, quayPlugin } from './plugin.esm.js';
2
+ export { isQuayAvailable } from './components/Router.esm.js';
3
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,90 @@
1
+ import { VulnerabilitySeverity, VulnerabilityOrder } from '../types.esm.js';
2
+
3
+ const SEVERITY_COLORS = new Proxy(
4
+ /* @__PURE__ */ new Map([
5
+ [VulnerabilitySeverity.Critical, "#7D1007"],
6
+ [VulnerabilitySeverity.High, "#C9190B"],
7
+ [VulnerabilitySeverity.Medium, "#EC7A08"],
8
+ [VulnerabilitySeverity.Low, "#F0AB00"],
9
+ [VulnerabilitySeverity.None, "#3E8635"]
10
+ ]),
11
+ {
12
+ get: (o, k) => o.has(k) ? o.get(k) : "#8A8D90"
13
+ }
14
+ );
15
+ const vulnerabilitySummary = (layer) => {
16
+ const summary = {};
17
+ layer?.Features.forEach((feature) => {
18
+ feature.Vulnerabilities?.forEach((vulnerability) => {
19
+ const { Severity } = vulnerability;
20
+ if (!summary[Severity]) {
21
+ summary[Severity] = 0;
22
+ }
23
+ summary[Severity]++;
24
+ });
25
+ });
26
+ const scanResults = Object.entries(summary).sort((a, b) => {
27
+ const severityA = VulnerabilityOrder[a[0]];
28
+ const severityB = VulnerabilityOrder[b[0]];
29
+ return severityA - severityB;
30
+ }).map(([severity, count]) => `${severity}: ${count}`).join(", ");
31
+ return scanResults.trim() !== "" ? scanResults : "Passed";
32
+ };
33
+ const securityScanOrder = [
34
+ "High",
35
+ "Medium",
36
+ "Low",
37
+ "Passed",
38
+ "Scanning",
39
+ "Queued",
40
+ "Unscanned",
41
+ "Unsupported"
42
+ ];
43
+ const capitalizeFirstLetter = (s) => {
44
+ return s.charAt(0).toLocaleUpperCase("en-US") + s.slice(1);
45
+ };
46
+ const securityScanComparator = (ar, br, order = "desc") => {
47
+ const a = vulnerabilitySummary(ar.securityDetails);
48
+ const b = vulnerabilitySummary(br.securityDetails);
49
+ const parseScan = (scan) => {
50
+ const values = {
51
+ High: 0,
52
+ Medium: 0,
53
+ Low: 0
54
+ };
55
+ scan.split(", ").forEach((part) => {
56
+ const [key, value] = part.split(": ");
57
+ if (values[key] !== void 0) {
58
+ values[key] = parseInt(value, 10);
59
+ }
60
+ });
61
+ return values;
62
+ };
63
+ const aParts = a.split(", ");
64
+ const bParts = b.split(", ");
65
+ const multiplier = order === "asc" ? 1 : -1;
66
+ if (aParts.length >= 1 && bParts.length >= 1 && aParts[0] !== "Passed" && bParts[0] !== "Passed") {
67
+ const aParsed = parseScan(a);
68
+ const bParsed = parseScan(b);
69
+ if (aParsed.High !== bParsed.High) {
70
+ return (bParsed.High - aParsed.High) * multiplier;
71
+ }
72
+ if (aParsed.Medium !== bParsed.Medium) {
73
+ return (bParsed.Medium - aParsed.Medium) * multiplier;
74
+ }
75
+ if (aParsed.Low !== bParsed.Low) {
76
+ return (bParsed.Low - aParsed.Low) * multiplier;
77
+ }
78
+ }
79
+ const finalAValue = capitalizeFirstLetter(
80
+ ar.securityStatus === "scanned" ? aParts[0].split(":")[0] : ar.securityStatus ?? "scanning"
81
+ );
82
+ const finalBValue = capitalizeFirstLetter(
83
+ br.securityStatus === "scanned" ? bParts[0].split(":")[0] : br.securityStatus ?? "scanning"
84
+ );
85
+ if (finalAValue === "Scanning" || finalBValue === "Scanning") return 1;
86
+ return (securityScanOrder.indexOf(finalAValue) - securityScanOrder.indexOf(finalBValue)) * multiplier;
87
+ };
88
+
89
+ export { SEVERITY_COLORS, capitalizeFirstLetter, securityScanComparator, vulnerabilitySummary };
90
+ //# sourceMappingURL=utils.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.esm.js","sources":["../../src/lib/utils.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n Layer,\n QuayTagData,\n VulnerabilityOrder,\n VulnerabilitySeverity,\n} from '../types';\n\nexport const SEVERITY_COLORS = new Proxy(\n new Map([\n [VulnerabilitySeverity.Critical, '#7D1007'],\n [VulnerabilitySeverity.High, '#C9190B'],\n [VulnerabilitySeverity.Medium, '#EC7A08'],\n [VulnerabilitySeverity.Low, '#F0AB00'],\n [VulnerabilitySeverity.None, '#3E8635'],\n ]) as any,\n {\n get: (o: Map<VulnerabilitySeverity, string>, k: VulnerabilitySeverity) =>\n o.has(k) ? o.get(k) : '#8A8D90',\n },\n);\n\nexport const vulnerabilitySummary = (layer: Layer): string => {\n const summary: Record<string, number> = {};\n\n layer?.Features.forEach(feature => {\n feature.Vulnerabilities?.forEach(vulnerability => {\n const { Severity } = vulnerability;\n if (!summary[Severity]) {\n summary[Severity] = 0;\n }\n summary[Severity]++;\n });\n });\n\n const scanResults = Object.entries(summary)\n .sort((a, b) => {\n const severityA = VulnerabilityOrder[a[0] as VulnerabilitySeverity];\n const severityB = VulnerabilityOrder[b[0] as VulnerabilitySeverity];\n\n return severityA - severityB;\n })\n .map(([severity, count]) => `${severity}: ${count}`)\n .join(', ');\n return scanResults.trim() !== '' ? scanResults : 'Passed';\n};\n\nconst securityScanOrder = [\n 'High',\n 'Medium',\n 'Low',\n 'Passed',\n 'Scanning',\n 'Queued',\n 'Unscanned',\n 'Unsupported',\n];\n\nexport const capitalizeFirstLetter = (s: string): string => {\n return s.charAt(0).toLocaleUpperCase('en-US') + s.slice(1);\n};\n\nexport const securityScanComparator = (\n ar: QuayTagData,\n br: QuayTagData,\n order: 'asc' | 'desc' = 'desc',\n) => {\n const a = vulnerabilitySummary(ar.securityDetails);\n const b = vulnerabilitySummary(br.securityDetails);\n\n const parseScan = (scan: string) => {\n const values: { [key: string]: number } = {\n High: 0,\n Medium: 0,\n Low: 0,\n };\n scan.split(', ').forEach((part: string) => {\n const [key, value] = part.split(': ');\n if (values[key] !== undefined) {\n values[key] = parseInt(value, 10);\n }\n });\n return values;\n };\n\n const aParts = a.split(', ');\n const bParts = b.split(', ');\n\n const multiplier = order === 'asc' ? 1 : -1;\n\n if (\n aParts.length >= 1 &&\n bParts.length >= 1 &&\n aParts[0] !== 'Passed' &&\n bParts[0] !== 'Passed'\n ) {\n const aParsed = parseScan(a);\n const bParsed = parseScan(b);\n\n if (aParsed.High !== bParsed.High) {\n return (bParsed.High - aParsed.High) * multiplier;\n }\n if (aParsed.Medium !== bParsed.Medium) {\n return (bParsed.Medium - aParsed.Medium) * multiplier;\n }\n if (aParsed.Low !== bParsed.Low) {\n return (bParsed.Low - aParsed.Low) * multiplier;\n }\n }\n\n const finalAValue = capitalizeFirstLetter(\n ar.securityStatus === 'scanned'\n ? aParts[0].split(':')[0]\n : ar.securityStatus ?? 'scanning',\n );\n\n const finalBValue = capitalizeFirstLetter(\n br.securityStatus === 'scanned'\n ? bParts[0].split(':')[0]\n : br.securityStatus ?? 'scanning',\n );\n\n if (finalAValue === 'Scanning' || finalBValue === 'Scanning') return 1;\n\n return (\n (securityScanOrder.indexOf(finalAValue) -\n securityScanOrder.indexOf(finalBValue)) *\n multiplier\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { createPlugin, createApiFactory, discoveryApiRef, configApiRef, identityApiRef, createRoutableExtension } from '@backstage/core-plugin-api';
2
+ import { quayApiRef, QuayApiClient } from './api/index.esm.js';
3
+ import './hooks/quay.esm.js';
4
+ import { rootRouteRef, tagRouteRef } from './routes.esm.js';
5
+
6
+ const quayPlugin = createPlugin({
7
+ id: "quay",
8
+ routes: {
9
+ root: rootRouteRef,
10
+ tag: tagRouteRef
11
+ },
12
+ apis: [
13
+ createApiFactory({
14
+ api: quayApiRef,
15
+ deps: {
16
+ discoveryApi: discoveryApiRef,
17
+ configApi: configApiRef,
18
+ identityApi: identityApiRef
19
+ },
20
+ factory: ({ discoveryApi, configApi, identityApi }) => new QuayApiClient({ discoveryApi, configApi, identityApi })
21
+ })
22
+ ]
23
+ });
24
+ const QuayPage = quayPlugin.provide(
25
+ createRoutableExtension({
26
+ name: "QuayPage",
27
+ component: () => import('./components/Router.esm.js').then((m) => m.Router),
28
+ mountPoint: rootRouteRef
29
+ })
30
+ );
31
+
32
+ export { QuayPage, quayPlugin };
33
+ //# sourceMappingURL=plugin.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity } from '@backstage/catalog-model';\nimport {\n configApiRef,\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { QuayApiClient, quayApiRef } from './api';\nimport { QUAY_ANNOTATION_REPOSITORY } from './hooks';\nimport { rootRouteRef, tagRouteRef } from './routes';\n\n/**\n * Quay plugin\n *\n * @public\n */\nexport const quayPlugin = createPlugin({\n id: 'quay',\n routes: {\n root: rootRouteRef,\n tag: tagRouteRef,\n },\n apis: [\n createApiFactory({\n api: quayApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n configApi: configApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, configApi, identityApi }) =>\n new QuayApiClient({ discoveryApi, configApi, identityApi }),\n }),\n ],\n});\n\n/**\n * Quay page\n *\n * @public\n */\nexport const QuayPage = quayPlugin.provide(\n createRoutableExtension({\n name: 'QuayPage',\n component: () => import('./components/Router').then(m => m.Router),\n mountPoint: rootRouteRef,\n }),\n);\n\n/**\n * Returns true if the catalog entity contains the quay annotation `quay.io/repository-slug`.\n *\n * @public\n */\nexport const isQuayAvailable = (entity: Entity) =>\n Boolean(entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY]);\n"],"names":[],"mappings":";;;;;AAkCO,MAAM,aAAa,YAAa,CAAA;AAAA,EACrC,EAAI,EAAA,MAAA;AAAA,EACJ,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,YAAA;AAAA,IACN,GAAK,EAAA,WAAA;AAAA,GACP;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,gBAAiB,CAAA;AAAA,MACf,GAAK,EAAA,UAAA;AAAA,MACL,IAAM,EAAA;AAAA,QACJ,YAAc,EAAA,eAAA;AAAA,QACd,SAAW,EAAA,YAAA;AAAA,QACX,WAAa,EAAA,cAAA;AAAA,OACf;AAAA,MACA,OAAS,EAAA,CAAC,EAAE,YAAA,EAAc,SAAW,EAAA,WAAA,EACnC,KAAA,IAAI,aAAc,CAAA,EAAE,YAAc,EAAA,SAAA,EAAW,aAAa,CAAA;AAAA,KAC7D,CAAA;AAAA,GACH;AACF,CAAC,EAAA;AAOM,MAAM,WAAW,UAAW,CAAA,OAAA;AAAA,EACjC,uBAAwB,CAAA;AAAA,IACtB,IAAM,EAAA,UAAA;AAAA,IACN,SAAA,EAAW,MAAM,OAAO,4BAAqB,EAAE,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,MAAM,CAAA;AAAA,IACjE,UAAY,EAAA,YAAA;AAAA,GACb,CAAA;AACH;;;;"}
@@ -0,0 +1,13 @@
1
+ import { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api';
2
+
3
+ const rootRouteRef = createRouteRef({
4
+ id: "quay"
5
+ });
6
+ const tagRouteRef = createSubRouteRef({
7
+ id: "quay-tag",
8
+ parent: rootRouteRef,
9
+ path: "/tag/:digest"
10
+ });
11
+
12
+ export { rootRouteRef, tagRouteRef };
13
+ //# sourceMappingURL=routes.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.esm.js","sources":["../src/routes.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'quay',\n});\n\nexport const tagRouteRef = createSubRouteRef({\n id: 'quay-tag',\n parent: rootRouteRef,\n path: '/tag/:digest',\n});\n"],"names":[],"mappings":";;AAiBO,MAAM,eAAe,cAAe,CAAA;AAAA,EACzC,EAAI,EAAA,MAAA;AACN,CAAC,EAAA;AAEM,MAAM,cAAc,iBAAkB,CAAA;AAAA,EAC3C,EAAI,EAAA,UAAA;AAAA,EACJ,MAAQ,EAAA,YAAA;AAAA,EACR,IAAM,EAAA,cAAA;AACR,CAAC;;;;"}
@@ -0,0 +1,22 @@
1
+ var VulnerabilitySeverity = /* @__PURE__ */ ((VulnerabilitySeverity2) => {
2
+ VulnerabilitySeverity2["Critical"] = "Critical";
3
+ VulnerabilitySeverity2["High"] = "High";
4
+ VulnerabilitySeverity2["Medium"] = "Medium";
5
+ VulnerabilitySeverity2["Low"] = "Low";
6
+ VulnerabilitySeverity2["Negligible"] = "Negligible";
7
+ VulnerabilitySeverity2["None"] = "None";
8
+ VulnerabilitySeverity2["Unknown"] = "Unknown";
9
+ return VulnerabilitySeverity2;
10
+ })(VulnerabilitySeverity || {});
11
+ const VulnerabilityOrder = {
12
+ ["Critical" /* Critical */]: 0,
13
+ ["High" /* High */]: 1,
14
+ ["Medium" /* Medium */]: 2,
15
+ ["Low" /* Low */]: 3,
16
+ ["Negligible" /* Negligible */]: 4,
17
+ ["None" /* None */]: 5,
18
+ ["Unknown" /* Unknown */]: 6
19
+ };
20
+
21
+ export { VulnerabilityOrder, VulnerabilitySeverity };
22
+ //# sourceMappingURL=types.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.esm.js","sources":["../src/types.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport interface TagsResponse {\n page: number;\n has_additional: boolean;\n tags: Tag[];\n}\n\nexport interface Tag {\n name: string;\n is_manifest_list: boolean;\n last_modified: string;\n manifest_digest: string;\n reversion: boolean;\n size: number;\n start_ts?: number;\n end_ts?: number;\n manifest_list?: ManifestList;\n expiration?: string;\n}\n\nexport interface LabelsResponse {\n labels: Label[];\n}\nexport interface QuayTagData {\n id: string;\n name: string;\n last_modified: string;\n size: string;\n rawSize: number;\n manifest_digest: React.JSX.Element;\n expiration?: string;\n securityDetails: Layer;\n securityStatus: string;\n manifest_digest_raw: string;\n}\nexport interface Label {\n id: string;\n key: string;\n value: string;\n source_type: string;\n media_type: string;\n}\n\nexport interface ManifestList {\n schemaVersion: number;\n mediaType: string;\n manifests: Manifest[];\n}\n\nexport interface Manifest {\n mediaType: string;\n size: number;\n digest: string;\n platform: Platform;\n security: SecurityDetailsResponse;\n layers: Layer[];\n}\n\nexport interface Platform {\n architecture: string;\n os: string;\n features?: string[];\n variant?: string;\n 'os.version'?: string;\n}\n\nexport interface SecurityDetailsResponse {\n status: 'unsupported' | 'unscanned' | 'scanning' | 'scanned' | 'queued';\n data: Data | null;\n}\nexport interface Data {\n Layer: Layer;\n}\nexport interface Layer {\n Name: string;\n ParentName: string;\n NamespaceName: string;\n IndexedByVersion: number;\n Features: Feature[];\n}\nexport interface Feature {\n Name: string;\n VersionFormat: string;\n NamespaceName: string;\n AddedBy: string;\n Version: string;\n Vulnerabilities?: Vulnerability[];\n BaseScores?: number[];\n CVEIds?: string[];\n}\n\nexport interface Vulnerability {\n Severity: VulnerabilitySeverity;\n NamespaceName: string;\n Link: string;\n FixedBy: string;\n Description: string;\n Name: string;\n Metadata: VulnerabilityMetadata;\n}\n\nexport interface VulnerabilityMetadata {\n UpdatedBy: string;\n RepoName: string | null;\n RepoLink: string | null;\n DistroName: string;\n DistroVersion: string;\n NVD: {\n CVSSv3: {\n Vectors: string;\n Score: number | string;\n };\n };\n}\n\nexport enum VulnerabilitySeverity {\n Critical = 'Critical',\n High = 'High',\n Medium = 'Medium',\n Low = 'Low',\n Negligible = 'Negligible',\n None = 'None',\n Unknown = 'Unknown',\n}\n\nexport const VulnerabilityOrder = {\n [VulnerabilitySeverity.Critical]: 0,\n [VulnerabilitySeverity.High]: 1,\n [VulnerabilitySeverity.Medium]: 2,\n [VulnerabilitySeverity.Low]: 3,\n [VulnerabilitySeverity.Negligible]: 4,\n [VulnerabilitySeverity.None]: 5,\n [VulnerabilitySeverity.Unknown]: 6,\n};\n\nexport interface ManifestByDigestResponse {\n digest: string;\n is_manifest_list: boolean;\n manifest_data: string;\n config_media_type: string;\n layers: LayerByDigest[];\n layers_compressed_size: number;\n}\n\nexport interface LayerByDigest {\n index: number;\n compressed_size: number;\n is_remote: boolean;\n urls: string[] | null;\n command: string[] | null;\n comment: string | null;\n author: string | null;\n blob_digest: string;\n created_datetime: string;\n}\n\nexport interface VulnerabilityListItem extends Vulnerability {\n PackageName: string;\n CurrentVersion: string;\n}\n"],"names":["VulnerabilitySeverity"],"mappings":"AAiIY,IAAA,qBAAA,qBAAAA,sBAAL,KAAA;AACL,EAAAA,uBAAA,UAAW,CAAA,GAAA,UAAA,CAAA;AACX,EAAAA,uBAAA,MAAO,CAAA,GAAA,MAAA,CAAA;AACP,EAAAA,uBAAA,QAAS,CAAA,GAAA,QAAA,CAAA;AACT,EAAAA,uBAAA,KAAM,CAAA,GAAA,KAAA,CAAA;AACN,EAAAA,uBAAA,YAAa,CAAA,GAAA,YAAA,CAAA;AACb,EAAAA,uBAAA,MAAO,CAAA,GAAA,MAAA,CAAA;AACP,EAAAA,uBAAA,SAAU,CAAA,GAAA,SAAA,CAAA;AAPA,EAAAA,OAAAA,sBAAAA,CAAAA;AAAA,CAAA,EAAA,qBAAA,IAAA,EAAA,EAAA;AAUL,MAAM,kBAAqB,GAAA;AAAA,EAChC,CAAC,4BAAiC,CAAA;AAAA,EAClC,CAAC,oBAA6B,CAAA;AAAA,EAC9B,CAAC,wBAA+B,CAAA;AAAA,EAChC,CAAC,kBAA4B,CAAA;AAAA,EAC7B,CAAC,gCAAmC,CAAA;AAAA,EACpC,CAAC,oBAA6B,CAAA;AAAA,EAC9B,CAAC,0BAAgC,CAAA;AACnC;;;;"}
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "@backstage-community/plugin-quay",
3
+ "version": "1.14.2",
4
+ "main": "dist/index.esm.js",
5
+ "types": "dist/index.d.ts",
6
+ "license": "Apache-2.0",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.esm.js",
10
+ "types": "dist/index.d.ts"
11
+ },
12
+ "backstage": {
13
+ "role": "frontend-plugin",
14
+ "supported-versions": "1.32.5",
15
+ "pluginId": "quay",
16
+ "pluginPackage": "@backstage-community/plugin-quay",
17
+ "pluginPackages": [
18
+ "@backstage-community/plugin-quay",
19
+ "@backstage-community/plugin-quay-common"
20
+ ]
21
+ },
22
+ "sideEffects": false,
23
+ "scripts": {
24
+ "build": "backstage-cli package build",
25
+ "clean": "backstage-cli package clean",
26
+ "lint:check": "backstage-cli package lint",
27
+ "lint:fix": "backstage-cli package lint --fix",
28
+ "postpack": "backstage-cli package postpack",
29
+ "prepack": "backstage-cli package prepack",
30
+ "prepare": "",
31
+ "start": "backstage-cli package start",
32
+ "test": "backstage-cli package test --passWithNoTests --coverage",
33
+ "tsc": "tsc",
34
+ "prettier:check": "prettier --ignore-unknown --check .",
35
+ "prettier:fix": "prettier --ignore-unknown --write .",
36
+ "ui-test": "start-server-and-test start localhost:3000 'playwright test'"
37
+ },
38
+ "dependencies": {
39
+ "@backstage-community/plugin-quay-common": "^1.3.2",
40
+ "@backstage/catalog-model": "^1.7.0",
41
+ "@backstage/core-components": "^0.15.1",
42
+ "@backstage/core-plugin-api": "^1.10.0",
43
+ "@backstage/plugin-catalog-common": "^1.1.0",
44
+ "@backstage/plugin-catalog-react": "^1.14.0",
45
+ "@backstage/plugin-permission-react": "^0.4.27",
46
+ "@backstage/theme": "^0.6.0",
47
+ "@janus-idp/shared-react": "^2.13.1",
48
+ "@material-ui/core": "^4.12.2",
49
+ "@material-ui/icons": "^4.11.3",
50
+ "@material-ui/lab": "4.0.0-alpha.61",
51
+ "react-use": "^17.4.0"
52
+ },
53
+ "peerDependencies": {
54
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0",
55
+ "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
56
+ "react-router-dom": "^6.0.0"
57
+ },
58
+ "devDependencies": {
59
+ "@backstage/cli": "0.28.2",
60
+ "@backstage/core-app-api": "1.15.1",
61
+ "@backstage/dev-utils": "1.1.2",
62
+ "@backstage/test-utils": "1.7.0",
63
+ "@playwright/test": "1.45.3",
64
+ "@redhat-developer/red-hat-developer-hub-theme": "0.4.0",
65
+ "@spotify/prettier-config": "^15.0.0",
66
+ "@testing-library/dom": "^10.0.0",
67
+ "@testing-library/jest-dom": "^6.0.0",
68
+ "@testing-library/react": "^15.0.0",
69
+ "@testing-library/react-hooks": "8.0.1",
70
+ "@testing-library/user-event": "14.5.2",
71
+ "@types/node": "18.19.34",
72
+ "@types/react": "^18.2.58",
73
+ "@types/react-dom": "^18.2.19",
74
+ "cross-fetch": "4.0.0",
75
+ "msw": "1.3.3",
76
+ "prettier": "3.3.3",
77
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0",
78
+ "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
79
+ "react-router-dom": "^6.0.0",
80
+ "start-server-and-test": "2.0.8"
81
+ },
82
+ "files": [
83
+ "app-config.dynamic.yaml",
84
+ "config.d.ts",
85
+ "dist"
86
+ ],
87
+ "configSchema": "config.d.ts",
88
+ "repository": {
89
+ "type": "git",
90
+ "url": "https://github.com/backstage/community-plugins",
91
+ "directory": "workspaces/quay/plugins/quay"
92
+ },
93
+ "keywords": [
94
+ "support:production",
95
+ "lifecycle:active",
96
+ "backstage",
97
+ "plugin"
98
+ ],
99
+ "homepage": "https://red.ht/rhdh",
100
+ "bugs": "https://github.com/backstage/community-plugins/issues",
101
+ "maintainers": [
102
+ "@karthikjeeyar"
103
+ ],
104
+ "author": "Red Hat",
105
+ "module": "./dist/index.esm.js"
106
+ }