The Reports API module provides comprehensive report management functionality for Rapid7 InsightVM, including:
- Report Configuration Management: Create, read, update, and delete report configurations
- Report Generation: Generate reports on-demand with customizable parameters
- Report History & Instances: Track report generation history and manage instances
- Report Downloads: Download generated report content (typically GZip compressed)
- Templates & Formats: Discover available report templates and output formats
- Helper Methods: Convenience methods for common workflows
from rapid7 import InsightVMClient
# Initialize client
client = InsightVMClient()
# List all reports
reports = client.reports.list()
# Generate a report
instance_id = client.reports.generate(report_id=42)
# Wait for completion and download
instance = client.reports.wait_for_completion(42, instance_id)
content = client.reports.download(42, instance_id)
# Save to file
with open("report.pdf.gz", "wb") as f:
f.write(content)Retrieve all configured reports with pagination:
# Get first page of reports
reports = client.reports.list(page=0, size=100)
for report in reports['resources']:
print(f"{report['id']}: {report['name']}")
print(f" Format: {report['format']}")
print(f" Template: {report.get('template', 'N/A')}")Retrieve configuration details for a specific report:
report = client.reports.get_report(42)
print(f"Name: {report['name']}")
print(f"Format: {report['format']}")
print(f"Template: {report.get('template')}")
print(f"Owner: {report['owner']}")
# Check scope
scope = report.get('scope', {})
if 'sites' in scope:
print(f"Sites: {scope['sites']}")
if 'assetGroups' in scope:
print(f"Asset Groups: {scope['assetGroups']}")Create a new report configuration:
# Basic PDF report for specific sites
config = {
"name": "Monthly Security Report",
"format": "pdf",
"template": "executive-overview",
"scope": {
"sites": [42, 43, 44]
}
}
result = client.reports.create(config)
report_id = result['id']
print(f"Created report ID: {report_id}")
# Advanced configuration with filters and scheduling
advanced_config = {
"name": "Weekly Vulnerability Report",
"format": "pdf",
"template": "audit-report",
"scope": {
"assetGroups": [10, 20]
},
"filters": {
"severity": "critical,severe",
"statuses": ["vulnerable"]
},
"frequency": {
"type": "schedule",
"start": "2025-01-15T00:00:00Z",
"repeat": {
"every": "date-of-month",
"interval": 1,
"dayOfWeek": "monday"
}
},
"email": {
"owner": "file",
"additionalRecipients": ["security@company.com"]
}
}
result = client.reports.create(advanced_config)Update an existing report configuration:
# Update report name and scope
updated_config = {
"name": "Updated Report Name",
"scope": {
"sites": [42, 43, 44, 45] # Added site 45
}
}
client.reports.update(42, updated_config)Delete a report configuration:
client.reports.delete_report(42)Trigger on-demand report generation:
# Generate report and get instance ID
instance_id = client.reports.generate(42)
print(f"Report generation started: Instance {instance_id}")
# Check status
instance = client.reports.get_instance(42, instance_id)
print(f"Status: {instance['status']}")Block until report generation completes:
# Start generation
instance_id = client.reports.generate(42)
# Wait for completion (polls every 30 seconds by default)
final_instance = client.reports.wait_for_completion(
report_id=42,
instance_id=instance_id,
poll_interval=60, # Check every minute
timeout=3600 # Give up after 1 hour
)
print(f"Report completed: {final_instance['status']}")
print(f"Size: {final_instance['size']['formatted']}")
print(f"Generated: {final_instance['generated']}")Quick check if a report is complete:
if client.reports.is_complete(42, "12345"):
print("Report is ready for download")
content = client.reports.download(42, "12345")
else:
print("Report is still generating...")Convenience method that combines generation, waiting, and download:
# One-step generation and download
content = client.reports.generate_and_download(
report_id=42,
poll_interval=60,
timeout=3600
)
# Save to file
with open("security_report.pdf.gz", "wb") as f:
f.write(content)
# If you need to decompress
import gzip
with gzip.open("security_report.pdf.gz", "rb") as f:
pdf_content = f.read()
with open("security_report.pdf", "wb") as f:
f.write(pdf_content)Retrieve all historical generations of a report:
history = client.reports.get_history(42)
print(f"Total instances: {len(history['resources'])}")
for instance in history['resources']:
print(f"Instance {instance['id']}:")
print(f" Status: {instance['status']}")
print(f" Generated: {instance['generated']}")
print(f" Size: {instance['size']['formatted']}")Get details for a specific report instance:
instance = client.reports.get_instance(42, "12345")
print(f"Status: {instance['status']}")
print(f"Generated: {instance['generated']}")
print(f"Size: {instance['size']['formatted']}")
print(f"Download URI: {instance.get('uri')}")Get the most recent report generation:
latest = client.reports.get_latest_instance(42)
if latest:
print(f"Latest generation: {latest['generated']}")
print(f"Status: {latest['status']}")
if latest['status'] == 'complete':
content = client.reports.download(42, latest['id'])
else:
print("No report instances found")Remove a specific report generation from history:
# Delete old report instance
client.reports.delete_instance(42, "12345")Download the generated report file:
# Download report (usually GZip compressed)
content = client.reports.download(42, "12345")
# Save compressed file
with open("report.pdf.gz", "wb") as f:
f.write(content)
# Or decompress and save
import gzip
import io
with gzip.GzipFile(fileobj=io.BytesIO(content)) as gz:
pdf_content = gz.read()
with open("report.pdf", "wb") as f:
f.write(pdf_content)Get all available report templates:
templates = client.reports.get_templates()
print("Available Templates:")
for template in templates['resources']:
print(f"\n{template['id']}: {template['name']}")
print(f" Type: {template['type']}")
print(f" Built-in: {template['builtin']}")
print(f" Description: {template['description']}")
if 'sections' in template:
print(f" Sections: {', '.join(template['sections'])}")Common templates include:
executive-overview- High-level summary for executivesaudit-report- Comprehensive audit detailsbaseline-comparison- Compare against baselinepci-attestation- PCI DSS compliance reporthipaa-compliance- HIPAA compliance report
Get details for a specific template:
template = client.reports.get_template("executive-overview")
print(f"Name: {template['name']}")
print(f"Description: {template['description']}")
print(f"Type: {template['type']}")
print(f"Sections: {template.get('sections', [])}")Get all available output formats:
formats = client.reports.get_formats()
print("Available Formats:")
for fmt in formats['resources']:
print(f"\nFormat: {fmt['format']}")
if 'templates' in fmt:
print(f" Supported templates: {len(fmt['templates'])}")
print(f" Templates: {', '.join(fmt['templates'][:5])}...")Common formats include:
pdf- Adobe PDFhtml- HTML documentrtf- Rich Text Formatxml- XML formatcsv- Comma-separated valuesdb- Database format
Retrieve all reports with automatic pagination:
all_reports = client.reports.get_all_reports()
print(f"Total reports: {len(all_reports)}")
for report in all_reports:
print(f"{report['id']}: {report['name']}")Generate and email reports on a schedule:
# Create scheduled monthly report
config = {
"name": "Monthly Security Summary",
"format": "pdf",
"template": "executive-overview",
"scope": {
"sites": [42, 43, 44]
},
"frequency": {
"type": "schedule",
"start": "2025-01-01T09:00:00Z",
"repeat": {
"every": "date-of-month",
"interval": 1 # First of month
}
},
"email": {
"owner": "file",
"additionalRecipients": [
"ciso@company.com",
"security-team@company.com"
],
"smtp": {
"global": True
}
}
}
result = client.reports.create(config)
print(f"Created scheduled report: {result['id']}")Generate a vulnerability report for specific assets:
# Create report configuration
config = {
"name": "Critical Vulnerabilities - Production",
"format": "pdf",
"template": "audit-report",
"scope": {
"assetGroups": [10] # Production assets
},
"filters": {
"severity": "critical,severe",
"statuses": ["vulnerable"]
}
}
# Create and generate immediately
result = client.reports.create(config)
report_id = result['id']
# Generate and download
content = client.reports.generate_and_download(
report_id=report_id,
timeout=1800 # 30 minutes
)
# Save report
filename = f"critical_vulns_{report_id}.pdf.gz"
with open(filename, "wb") as f:
f.write(content)
print(f"Report saved: {filename}")Generate PCI DSS compliance reports:
# PCI compliance report
config = {
"name": "PCI DSS Quarterly Compliance",
"format": "pdf",
"template": "pci-attestation",
"scope": {
"assetGroups": [5] # PCI scope assets
},
"filters": {
"categories": {
"included": ["PCI"]
}
}
}
result = client.reports.create(config)
report_id = result['id']
# Generate report
instance_id = client.reports.generate(report_id)
# Wait and download
instance = client.reports.wait_for_completion(
report_id,
instance_id,
timeout=3600
)
content = client.reports.download(report_id, instance_id)
with open("pci_compliance.pdf.gz", "wb") as f:
f.write(content)Clean up old report instances to save space:
import datetime
# Get report history
history = client.reports.get_history(42)
# Delete instances older than 90 days
cutoff = datetime.datetime.now() - datetime.timedelta(days=90)
for instance in history['resources']:
generated = datetime.datetime.fromisoformat(
instance['generated'].replace('Z', '+00:00')
)
if generated < cutoff:
print(f"Deleting old instance: {instance['id']}")
client.reports.delete_instance(42, str(instance['id']))-
Use Descriptive Names: Make report names clear and specific
# Good "Monthly Critical Vulnerabilities - Production Servers" # Bad "Report 1"
-
Set Appropriate Scope: Limit reports to relevant assets
config = { "scope": { "assetGroups": [10, 20], # Specific groups "tags": [5] # Or by tags } }
-
Apply Filters: Reduce noise by filtering results
config = { "filters": { "severity": "critical,severe", "statuses": ["vulnerable"] } }
-
Use Timeouts: Always set reasonable timeouts
instance = client.reports.wait_for_completion( report_id=42, instance_id=str(instance_id), timeout=3600 # Don't wait forever )
-
Handle Errors Gracefully:
try: content = client.reports.generate_and_download( report_id=42, timeout=1800 ) except TimeoutError: print("Report generation timed out") except RuntimeError as e: print(f"Report generation failed: {e}")
-
Check Status Before Download:
if client.reports.is_complete(42, instance_id): content = client.reports.download(42, instance_id)
- Clean Up Old Instances: Regularly delete old report instances
- Decompress When Needed: Reports are typically GZip compressed
- Use Descriptive Filenames: Include report ID and date
- Use Scheduled Reports: For recurring needs, use built-in scheduling
- Set Appropriate Times: Schedule during off-peak hours
- Configure Email Delivery: Automate distribution
import requests
try:
# Create report
result = client.reports.create(config)
# Generate report
instance_id = client.reports.generate(result['id'])
# Wait for completion
instance = client.reports.wait_for_completion(
result['id'],
instance_id,
timeout=3600
)
# Download
content = client.reports.download(result['id'], instance_id)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print("Report not found")
elif e.response.status_code == 401:
print("Authentication failed")
elif e.response.status_code == 400:
print(f"Bad request: {e.response.text}")
else:
print(f"HTTP error: {e}")
except TimeoutError as e:
print(f"Report generation timed out: {e}")
except RuntimeError as e:
print(f"Report generation failed: {e}")
except Exception as e:
print(f"Unexpected error: {e}")For SQL-based reports (database format):
config = {
"name": "Custom SQL Report",
"format": "db",
"query": """
SELECT
a.ip_address,
a.host_name,
a.risk_score,
COUNT(v.vulnerability_id) as vuln_count
FROM
dim_asset a
LEFT JOIN
fact_asset_vulnerability v ON a.asset_id = v.asset_id
GROUP BY
a.asset_id
HAVING
vuln_count > 0
ORDER BY
a.risk_score DESC
"""
}Compare current state against a baseline:
config = {
"name": "Baseline Comparison",
"format": "pdf",
"template": "baseline-comparison",
"baseline": {
"type": "previous_scan",
"scan_id": 12345
},
"scope": {
"sites": [42]
}
}Generate reports across multiple sites:
# Get all sites
all_sites = client.sites.get_all_sites()
# Create report for all sites
config = {
"name": "Enterprise-Wide Vulnerability Report",
"format": "pdf",
"template": "executive-overview",
"scope": {
"sites": [site['id'] for site in all_sites]
}
}
result = client.reports.create(config)For complete method signatures and parameters, see the ReportsAPI class documentation.
list()- List all report configurationsget_report()- Get report detailscreate()- Create new reportupdate()- Update report configurationdelete_report()- Delete reportgenerate()- Generate report instanceget_history()- Get report generation historyget_instance()- Get instance detailsdelete_instance()- Delete report instancedownload()- Download report contentget_templates()- List available templatesget_template()- Get template detailsget_formats()- List available formatswait_for_completion()- Wait for generationis_complete()- Check completion statusget_latest_instance()- Get most recent instanceget_all_reports()- Get all reports (paginated)generate_and_download()- Generate and download