diff --git a/.github/workflows/infrascan-ci.yml b/.github/workflows/infrascan-ci.yml index a22eb55..e60b668 100644 --- a/.github/workflows/infrascan-ci.yml +++ b/.github/workflows/infrascan-ci.yml @@ -17,7 +17,7 @@ jobs: chmod 777 infrascan-reports - name: Run InfraScan - uses: soldevelo/infrascan@v1.0.5 + uses: soldevelo/infrascan@v1.0.6 with: scanner: comprehensive format: html diff --git a/README.md b/README.md index 82460b8..be647e6 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v4 - name: Run InfraScan - uses: soldevelo/infrascan@v1.0.5 + uses: soldevelo/infrascan@v1.0.6 with: scanner: comprehensive format: html diff --git a/cli.py b/cli.py index a582100..d11576b 100755 --- a/cli.py +++ b/cli.py @@ -19,7 +19,7 @@ def init(*args, **kwargs): pass from reporter.grading import ReportGenerator from reporter.html_generator import generate_standalone_html -__version__ = "1.0.5" +__version__ = "1.0.6" # Setup basic logging logging.basicConfig(level=logging.ERROR, format='%(levelname)s: %(message)s') diff --git a/docs/PIPELINE_INTEGRATION.md b/docs/PIPELINE_INTEGRATION.md index 13ada85..8dccf7e 100644 --- a/docs/PIPELINE_INTEGRATION.md +++ b/docs/PIPELINE_INTEGRATION.md @@ -85,7 +85,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run Scan - uses: soldevelo/infrascan@v1.0.5 + uses: soldevelo/infrascan@v1.0.6 with: format: html out: report.html @@ -143,7 +143,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run K8s Scan - uses: soldevelo/infrascan@v1.0.5 + uses: soldevelo/infrascan@v1.0.6 with: framework: kubernetes scanner: comprehensive diff --git a/examples/pipelines/github-actions-k8s.yml b/examples/pipelines/github-actions-k8s.yml index af79dc2..67c778f 100644 --- a/examples/pipelines/github-actions-k8s.yml +++ b/examples/pipelines/github-actions-k8s.yml @@ -25,7 +25,7 @@ jobs: chmod 777 infrascan-reports - name: Run InfraScan on Kubernetes YAMLs - uses: soldevelo/infrascan@v1.0.5 + uses: soldevelo/infrascan@v1.0.6 with: scanner: comprehensive framework: kubernetes diff --git a/examples/pipelines/github-actions.yml b/examples/pipelines/github-actions.yml index 39063b5..46985e4 100644 --- a/examples/pipelines/github-actions.yml +++ b/examples/pipelines/github-actions.yml @@ -24,7 +24,7 @@ jobs: chmod 777 infrascan-reports - name: Run InfraScan - uses: soldevelo/infrascan@v1.0.5 + uses: soldevelo/infrascan@v1.0.6 with: scanner: comprehensive format: html diff --git a/reporter/html_generator.py b/reporter/html_generator.py index 7845cbd..39eae99 100644 --- a/reporter/html_generator.py +++ b/reporter/html_generator.py @@ -16,6 +16,7 @@ def generate_standalone_html(report_dict): js_path = os.path.join(base_dir, 'static', 'app.js') pdf_js_path = os.path.join(base_dir, 'static', 'pdf_generator.js') logo_path = os.path.join(base_dir, 'static', 'images', 'soldevelo.png') + logo_main_path = os.path.join(base_dir, 'static', 'images', 'logo_transparent.png') # Read files try: @@ -33,6 +34,9 @@ def generate_standalone_html(report_dict): with open(logo_path, 'rb') as f: logo_b64 = base64.b64encode(f.read()).decode('utf-8') + + with open(logo_main_path, 'rb') as f: + logo_main_b64 = base64.b64encode(f.read()).decode('utf-8') except Exception as e: import logging logging.error(f"Failed to read assets for HTML generation: {e}") @@ -54,9 +58,11 @@ def generate_standalone_html(report_dict): ) # Images (base64) - replace all occurrences - logo_tag_pattern = r'\{\{\s*url_for\([\'"]static[\'"],\s*filename=[\'"]images/soldevelo\.png[\'"]\)\s*\}\}' - logo_data_uri = f"data:image/png;base64,{logo_b64}" - html_content = re.sub(logo_tag_pattern, lambda m: logo_data_uri, html_content) + soldevelo_logo_pattern = r'\{\{\s*url_for\([\'"]static[\'"],\s*filename=[\'"]images/soldevelo\.png[\'"]\)\s*\}\}' + infrascan_logo_pattern = r'\{\{\s*url_for\([\'"]static[\'"],\s*filename=[\'"]images/logo_transparent\.png[\'"]\)\s*\}\}' + + html_content = re.sub(soldevelo_logo_pattern, f"data:image/png;base64,{logo_b64}", html_content) + html_content = re.sub(infrascan_logo_pattern, f"data:image/png;base64,{logo_main_b64}", html_content) # Links index_tag_pattern = r'\{\{\s*url_for\([\'"]index[\'"]\)\s*\}\}' diff --git a/static/app.js b/static/app.js index d3421ec..2bc5e9a 100644 --- a/static/app.js +++ b/static/app.js @@ -91,6 +91,9 @@ function initApp() { displayResults(data.results, data.summary, data.metadata, gradeReport); + // Setup PDF export for standalone mode + setupPdfExport(); + // Hide elements that don't make sense in standalone report if (newScanBtn) newScanBtn.style.display = 'none'; if (shareBtn) shareBtn.style.display = 'none'; @@ -152,6 +155,54 @@ function initApp() { } } + function setupPdfExport() { + const exportPdfBtn = document.getElementById('export-pdf-btn'); + if (!exportPdfBtn) return; + + // Remove old listener if any (to prevent doubles) + const newBtn = exportPdfBtn.cloneNode(true); + exportPdfBtn.parentNode.replaceChild(newBtn, exportPdfBtn); + + newBtn.addEventListener('click', async () => { + if (!currentResults) return; + + newBtn.classList.add('exporting'); + newBtn.disabled = true; + newBtn.innerHTML = ' Preparing PDF...'; + + try { + const html = buildPdfDocument( + currentResults, + currentSummary, + currentMetadata, + currentGradeReport + ); + const win = window.open('', '_blank', 'width=1050,height=820,scrollbars=yes,resizable=yes'); + if (!win) { + alert('Popup blocked! Please allow popups for this site to export PDF.'); + return; + } + win.document.open(); + win.document.write(html); + win.document.close(); + win.focus(); + + // Wait for fonts to load before printing for perfect rendering + if (win.document.fonts) { + await win.document.fonts.ready; + } + win.print(); + } catch (e) { + console.error('PDF generation error:', e); + alert('Could not generate PDF: ' + e.message); + } finally { + newBtn.classList.remove('exporting'); + newBtn.disabled = false; + newBtn.innerHTML = ' Export PDF'; + } + }); + } + async function loadSharedResults() { const urlParams = new URLSearchParams(window.location.search); const scanId = urlParams.get('scan_id'); @@ -445,48 +496,8 @@ function initApp() { }); } - // Export PDF Button — opens a dedicated, beautifully formatted PDF document in a new window - const exportPdfBtn = document.getElementById('export-pdf-btn'); - if (exportPdfBtn) { - exportPdfBtn.addEventListener('click', async () => { - if (!currentResults) return; - - exportPdfBtn.classList.add('exporting'); - exportPdfBtn.disabled = true; - exportPdfBtn.innerHTML = ' Preparing PDF...'; - - try { - const html = buildPdfDocument( - currentResults, - currentSummary, - currentMetadata, - currentGradeReport - ); - const win = window.open('', '_blank', 'width=1050,height=820,scrollbars=yes,resizable=yes'); - if (!win) { - alert('Popup blocked! Please allow popups for this site to export PDF.'); - return; - } - win.document.open(); - win.document.write(html); - win.document.close(); - win.focus(); - - // Wait for fonts to load before printing for perfect rendering - if (win.document.fonts) { - await win.document.fonts.ready; - } - win.print(); - } catch (e) { - console.error('PDF generation error:', e); - alert('Could not generate PDF: ' + e.message); - } finally { - exportPdfBtn.classList.remove('exporting'); - exportPdfBtn.disabled = false; - exportPdfBtn.innerHTML = ' Export PDF'; - } - }); - } + // Export PDF Button + setupPdfExport(); function resetScanProgress() { diff --git a/templates/index.html b/templates/index.html index 397ea45..0a9007f 100644 --- a/templates/index.html +++ b/templates/index.html @@ -230,7 +230,7 @@
InfraScan v1.0.7 © 2026 SolDevelo. Advanced Infrastructure Auditor.
+InfraScan v1.0.6 © 2026 SolDevelo. Advanced Infrastructure Auditor.
This tool is Open Source – contributions are welcome!