Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/infrascan-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
4 changes: 2 additions & 2 deletions docs/PIPELINE_INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/pipelines/github-actions-k8s.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/pipelines/github-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 9 additions & 3 deletions reporter/html_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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}")
Expand All @@ -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*\}\}'
Expand Down
95 changes: 53 additions & 42 deletions static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 = '<span class="export-pdf-icon">⏳</span> 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 = '<span class="export-pdf-icon">⬇</span> Export PDF';
}
});
}

async function loadSharedResults() {
const urlParams = new URLSearchParams(window.location.search);
const scanId = urlParams.get('scan_id');
Expand Down Expand Up @@ -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 = '<span class="export-pdf-icon">⏳</span> 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 = '<span class="export-pdf-icon">⬇</span> Export PDF';
}
});
}
// Export PDF Button
setupPdfExport();


function resetScanProgress() {
Expand Down
4 changes: 2 additions & 2 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ <h2 class="recent-scans-title">🕒 Recent Scans</h2>
<div class="release-notes-container">
<div class="release-entry">
<div class="release-header">
<span class="version">v1.0.7</span>
<span class="version">v1.0.6</span>
<span class="date">May 13, 2026</span>
</div>
<ul class="release-list">
Expand Down Expand Up @@ -508,7 +508,7 @@ <h3>Need help implementing these fixes?</h3>
<button id="open-feedback-btn" class="text-link-btn">Leave Feedback</button>
</p>

<p>InfraScan v1.0.7 &copy; 2026 SolDevelo. Advanced Infrastructure Auditor.</p>
<p>InfraScan v1.0.6 &copy; 2026 SolDevelo. Advanced Infrastructure Auditor.</p>
<p style="font-size: 0.9rem; opacity: 0.8; margin-top:4px;">This tool is <a
href="https://github.com/SolDevelo/InfraScan" target="_blank"><strong>Open Source</strong></a> –
contributions are welcome!
Expand Down
Loading