diff --git a/community_images/common/templates/image_readme.j2 b/community_images/common/templates/image_readme.j2 index ccd4bf4a02..90b2e573aa 100644 --- a/community_images/common/templates/image_readme.j2 +++ b/community_images/common/templates/image_readme.j2 @@ -1,6 +1,4 @@ - -RapidFort - +[![RapidFort][rapidfort-logo-header-svg]][rapidfort-logo-header-link]
@@ -10,9 +8,8 @@ [![Slack][slack-badge]][slack-link] [![FOSSA Status][fossa-badge]][fossa-link] - -Zero cve images - + +[![Zero cve images][zero-cve-images-svg]][zero-cve-images-link]
@@ -26,22 +23,12 @@ RapidFort has optimized and hardened this {{ official_name }} container image. T This optimized image is functionally equivalent to [{{- source_image_provider }} {{ official_name -}}][source-image-repo-link] image but more secure with a significantly smaller software attack surface. -

- - Vulnerabilities by severity - -

+[![Vulnerabilities by severity][vulns-chart-svg]][vulns-chart-link] +[![Original vs. this image][savings-svg]][savings-link] -

- - Original vs. this image - -

+[![View Report][full-report-svg]][full-report-link] - -View Report -

@@ -77,9 +64,7 @@ docker run -e RF_ACCESS_TOKEN="your_access_token" image_name The runtime instructions for this hardened container image are the same as the official release. Follow the instructions provided with the [{{- source_image_provider }} {{ official_name -}}][source-image-repo-link]. - -View Detailed Instructions - +[![View Detailed Instructions][instructions-svg]][instructions-link]

@@ -97,9 +82,8 @@ RapidFort is the pioneering Software Attack Surface Management (SASM) platform i Vulnerability reports for RapidFort's hardened images are updated daily to include newly discovered vulnerabilities and fixes. - -View on GitHub - + +[![View on GitHub][view-github-svg]][view-github-link]

@@ -118,9 +102,7 @@ We are big fans of open-source software and secure software development. RapidFo Join our slack community for any questions. - -RapidFort Community Slack - +[![RapidFort Community Slack][slack-png]][slack-link] ## 🌟 Support this project @@ -140,6 +122,9 @@ Learn more about RapidFort's pioneering Software Attack Surface Management platf

+[rapidfort-logo-header-link]: {{ report_url -}}?utm_source=github&utm_medium=ci_view_report&utm_campaign=sep_01_sprint&utm_term={{- name -}}&utm_content=rapidfort_logo +[rapidfort-logo-header-svg]: https://raw.githubusercontent.com/rapidfort/community-images/main/contrib/logo_light.svg + [dh-rf-badge]: https://img.shields.io/badge/dockerhub-images-important.svg?logo=Docker @@ -169,4 +154,27 @@ Learn more about RapidFort's pioneering Software Attack Surface Management platf [source-image-repo-link]: {{ source_image_repo_link }} [rf-dh-image-link]: https://hub.docker.com/r/{{- rf_docker_link }} -[savings-link]: https://github.com/rapidfort/community-images/raw/main/community_images/ {{- github_location -}} /assets/savings.svg + + +[savings-svg]: https://github.com/rapidfort/community-images/raw/main/community_images/ {{- github_location -}} /assets/savings.svg +[savings-link]: {{ report_url -}}?utm_source=github&utm_medium=ci_view_report&utm_campaign=sep_01_sprint&utm_term={{- name -}}&utm_content=image_savings_link + +[vulns-chart-svg]: https://github.com/rapidfort/community-images/raw/main/community_images/ {{- github_location -}} /assets/vulns_charts.svg +[vulns-chart-link]: {{ report_url -}}?utm_source=github&utm_medium=ci_view_report&utm_campaign=sep_01_sprint&utm_term={{- name -}}&utm_content=vulns_charts + +[full-report-svg]: https://raw.githubusercontent.com/rapidfort/community-images/main/contrib/full_report.svg +[full-report-link]: {{ report_url -}}?utm_source=github&utm_medium=ci_view_report&utm_campaign=sep_01_sprint&utm_term={{- name -}}&utm_content=get_full_report_button + +[instructions-link]: {{- source_image_readme -}} +[instructions-svg]: https://raw.githubusercontent.com/rapidfort/community-images/main/contrib/view_details.svg + + +[zero-cve-images-link]: https://hub.rapidfort.com/repositories?utm_source=github&utm_medium=ci_view_report&utm_campaign=sep_01_sprint&utm_term={{- name -}}&utm_content=zero_vulns_cve +[zero-cve-images-svg]: https://raw.githubusercontent.com/rapidfort/community-images/main/contrib/zero_cve_images_link.svg + +[slack-link]: https://join.slack.com/t/rapidfortcommunity/shared_invite/zt-1g3wy28lv-DaeGexTQ5IjfpbmYW7Rm_Q +[slack-png]: https://raw.githubusercontent.com/rapidfort/community-images/main/contrib/github_banner.png + +[view-github-link]: https://github.com/rapidfort/community-images/tree/main/community_images/{{- github_location -}} +[view-github-svg]: https://raw.githubusercontent.com/rapidfort/community-images/main/contrib/view_github.svg + diff --git a/contrib/github_banner.png b/contrib/github_banner.png index d0e1089af6..44d1037cf9 100644 Binary files a/contrib/github_banner.png and b/contrib/github_banner.png differ diff --git a/report_shots/shots.js b/report_shots/shots.js index b9e0a7dd70..6b25ad5581 100644 --- a/report_shots/shots.js +++ b/report_shots/shots.js @@ -72,7 +72,7 @@ const generateCharts = async (imageName, platform, imageSavePath) => { // const sizeSavingsChartSVG = await generateSavingsChart('Attack surface', imageInfo.origImageSize, imageInfo.hardenedImageSize, true); // const contextualSeverityChart = await generateContextualSeverityChart(vulnsOriginalSummary) // const vulnsBySeverityChart = await generateVulnsBySeverityChart(vulnsOriginalSummary.default, vulnsHardenedSummary.default); - const {width, svg:vulnsCountChartSVG} = await generateVulnsCountChart(vulnsOriginalSummary.default); + const {width, svg:vulnsCountChartSVG} = await generateVulnsCountChart(vulnsHardenedSummary.default); const vulnsOriginalHardenedChartSVG = await generateVulnsOriginalHardenedChart(width, vulnsOriginalSummary.default, vulnsHardenedSummary.default); @@ -716,6 +716,13 @@ async function generateSavingsCardsCompound(savingsData) { // return back SVG as string }); + + // Adjust the width to 760px and set the height proportionally + draw.width(760); // Set the width to 760px + const { width, height } = draw.viewbox(); // Get original dimensions from viewBox + const newHeight = (760 / width) * height; // Scale height proportionally + draw.size(760, newHeight); // Set the new size on the SVG + return draw.svg(); } @@ -724,53 +731,59 @@ async function mergeSvgHorizontally(svgStrings, gap) { const { SVG, registerWindow } = await import('@svgdotjs/svg.js'); const { createSVGWindow } = await import('svgdom'); const window = createSVGWindow(); - const document = window.document; - registerWindow(window, document); - - const remainingCSSList = [] - const canvas = SVG(document.documentElement); - const uniqueCSSRules = new Set(); - let totalWidth = 0; - let maxHeight = 0; - let fontFaceCaptured = false; // Track if font-face has already been captured - - svgStrings.forEach((svgString, index) => { - // Extract all styles content - const styleMatch = svgString.match(/]*>([\s\S]*?)<\/style>/); - if (styleMatch && styleMatch[1]) { - let styleContent = styleMatch[1]; - // Extract `@font-face` and other CSS rules separately - const fontFaceRules = styleContent.match(/@font-face\s*{[^}]*}/g) || []; - const remainingCSS = styleContent.replace(/@font-face\s*{[^}]*}/g, '').trim(); - // Add only the first set of `@font-face` rules - if (!fontFaceCaptured) { - fontFaceRules.forEach(rule => uniqueCSSRules.add(rule)); - fontFaceCaptured = true; - } - remainingCSSList.push(remainingCSS); + const document = window.document; + registerWindow(window, document); + + const remainingCSSList = []; + const canvas = SVG(document.documentElement); + const uniqueCSSRules = new Set(); + let totalWidth = 0; + let maxHeight = 0; + let fontFaceCaptured = false; // Track if font-face has already been captured + + svgStrings.forEach((svgString, index) => { + // Extract all styles content + const styleMatch = svgString.match(/]*>([\s\S]*?)<\/style>/); + if (styleMatch && styleMatch[1]) { + let styleContent = styleMatch[1]; + // Extract `@font-face` and other CSS rules separately + const fontFaceRules = styleContent.match(/@font-face\s*{[^}]*}/g) || []; + const remainingCSS = styleContent.replace(/@font-face\s*{[^}]*}/g, '').trim(); + // Add only the first set of `@font-face` rules + if (!fontFaceCaptured) { + fontFaceRules.forEach(rule => uniqueCSSRules.add(rule)); + fontFaceCaptured = true; } - - const svgWithoutStyle = svgString.replace(/]*>([\s\S]*?)<\/style>/, ''); - const svg = SVG(svgWithoutStyle); + remainingCSSList.push(remainingCSS); + } - const width = svg.width(); - const height = svg.height(); + const svgWithoutStyle = svgString.replace(/]*>([\s\S]*?)<\/style>/, ''); + const svg = SVG(svgWithoutStyle); - if (index > 0) totalWidth += gap; - totalWidth += width; - maxHeight = Math.max(maxHeight, height); + const width = svg.width(); + const height = svg.height(); - svg.move(totalWidth - width, 0); - canvas.add(svg); - }); - // Construct the final style tag with unique rules - const combinedStyle = ``; + if (index > 0) totalWidth += gap; + svg.move(totalWidth, 0); // Move each SVG horizontally with the specified gap + totalWidth += width; + maxHeight = Math.max(maxHeight, height); + + canvas.add(svg); + }); + + // Construct the final style tag with unique rules + const combinedStyle = ``; + + // Add the combined styles to the canvas + canvas.svg(combinedStyle + canvas.svg()); - // Add the combined styles to the canvas and set the final canvas size - canvas.svg(combinedStyle + canvas.svg()); - canvas.size(totalWidth, maxHeight); + // Set the viewBox to scale down the combined SVG to a width of 760px + const scaleFactor = 760 / totalWidth; + const scaledHeight = maxHeight * scaleFactor; + canvas.viewbox(0, 0, totalWidth, maxHeight); // Set the viewBox based on the combined content size + canvas.size(760, scaledHeight); // Set the final scaled width and proportional height - return canvas.svg(); + return canvas.svg(); } async function main() { const imgListPath = process.argv[2] @@ -778,6 +791,7 @@ async function main() { const imgList = await fsPromise.readFile(imgListPath, { encoding: 'utf8' }); const imgListArray = imgList.split("\n"); + // const imgListArray = ['apache/bitnami']; for await (const imagePath of imgListArray) {