Skip to main content

Generate self-contained HTML vulnerability reports from Cloudsmith, Trivy, and Grype scan output

Project description

Generate self-contained HTML vulnerability reports from Cloudsmith, Trivy, and Grype.

License Python

Installation

Install from PyPI (Currently in beta):

pip install vulnly

Features

  • Generates polished, self-contained HTML reports from JSON input
  • Supports multiple scanner sources: Cloudsmith, Trivy, and Grype (auto-detected or via --source flag)
  • Repository summary reports — automatically detects Cloudsmith repo-level summaries and generates a dedicated overview report with package status breakdown, aggregate vulnerability counts, and per-package detail table
  • Dark and light colour themes via --theme flag
  • Interactive doughnut charts showing severity or status distribution (powered by Chart.js)
  • Severity stat cards (Total, Critical, High, Medium, Low)
  • Auto-generated executive summary and action-required alert box
  • Client-side search and filter buttons for the CVE / package table
  • Automatic linking for CVE IDs (NVD) and GHSA IDs (GitHub Advisories)
  • Customisable logo — supply via --logo flag or drop an image into assets/
  • Accepts input from a file or stdin (-), making it easy to pipe from other tools
  • Input validation with helpful warnings for malformed data
  • Zero external dependencies — uses only the Python standard library

Quick Start

vulnly sample_data.json

This reads sample_data.json and writes the report to reports/ (the default output directory).

Specify the scanner source

The tool auto-detects the input format, but you can be explicit:

vulnly scan.json --source trivy
vulnly scan.json --source grype
vulnly scan.json --source cloudsmith

If --source is specified and the input doesn't match the expected format, the tool exits with a clear error message.

Repository summary reports

Cloudsmith repo-level summary JSON is automatically detected and generates a dedicated repository overview report:

vulnly repo_summary.json

The output includes package status cards (vulnerable / no issues / not scanned), aggregate vulnerability severity breakdown, a status distribution chart, and a searchable/filterable package table.

Specify a custom output path

vulnly sample_data.json -o my_report.html

Custom logo

Use the --logo flag to supply a custom logo image. It will be embedded directly in the HTML report header as a base64 data URI:

vulnly sample_data.json --logo my-company-logo.png

Logo requirements:

Constraint Limit
Max file size 2 MB
Max dimensions 512 × 512 px
Recommended size 128 × 128 px to 256 × 256 px
Supported formats .png, .jpg, .jpeg, .gif, .svg, .webp, .ico

If a custom logo exceeds the file size or dimension limits, a warning is printed and the default Vulnly logo is used instead.

If no --logo is provided, the built-in Vulnly logo is used.

Theme

Choose between a dark (default) or light colour theme:

vulnly sample_data.json --theme light
vulnly sample_data.json --theme dark

Read from stdin

Pipe JSON directly from another command:

cat scan_output.json | vulnly -

Cloudsmith CLI

Pipe vulnerability scan results directly from the Cloudsmith CLI:

cloudsmith vulnerabilities WORKSPACE/REPO/PACKAGE_IDENTIFIER --output-format json | vulnly -

Trivy

Scan an image with Trivy and pipe directly to Vulnly:

trivy image -f json nginx:latest | vulnly --source trivy -

Grype

Scan an image with Grype and pipe directly to Vulnly:

grype nginx:latest -o json | vulnly --source grype -

Usage

usage: vulnly [-h] [-o OUTPUT]
              [--logo LOGO] [--theme {dark,light}]
              [--source SOURCE]
              input

Generate an HTML vulnerability report from a JSON input file.

positional arguments:
  input                 Path to the JSON file containing vulnerability data
                        (use '-' for stdin)

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output HTML file path (default: auto-generated in
                        reports/ subfolder)
  --logo LOGO           Path to a custom logo image (max 512×512px, 2 MB;
                        embedded as base64 in the report)
  --theme {dark,light}  Report colour theme (default: dark)
  --source SOURCE       Scanner source format: cloudsmith, trivy, grype
                        (auto-detected if omitted)

Input JSON Format

The generator accepts multiple input formats — it auto-detects which one you provide, or you can specify explicitly with --source.

1. Cloudsmith package format

Pass raw JSON output from the Cloudsmith CLI. The tool extracts namespace, repository, package metadata, scan target, and all vulnerabilities automatically.

The expected structure has a top-level data object containing package, scans, etc.:

{
    "data": {
        "created_at": "2025-06-09T08:39:20.441354Z",
        "identifier": "TZR5N4HaO7nTclhz",
        "package": {
            "name": "log4j",
            "url": "https://example.com/packages/my-org/java/wAoMy00juV6N/",
            "version": "28a05d8e..."
        },
        "scans": [
            {
                "target": "Java",
                "type": "jar",
                "results": [
                    {
                        "vulnerability_id": "CVE-2021-45046",
                        "severity": "Critical",
                        "title": "DoS in log4j 2.x...",
                        "package_name": "org.apache.logging.log4j:log4j-core",
                        "affected_version": { "version": "2.8.1" },
                        "fixed_version": { "version": "2.16.0, 2.12.2" },
                        "cvss_scores": null
                    }
                ]
            }
        ]
    }
}

2. Cloudsmith repository summary format

Pass the repo-level summary JSON from Cloudsmith. This is auto-detected and produces a repository overview report instead of a per-package vulnerability report:

{
    "data": {
        "owner": "my-org",
        "packages": [
            {
                "package": "cloudsmith.io/jdk:9ea72e62...",
                "slug_perm": "XXVmdsZn7OEh",
                "status": "vulnerable",
                "vulnerabilities": {
                    "critical": 0,
                    "high": 0,
                    "low": 1,
                    "medium": 2,
                    "unknown": 0
                }
            },
            {
                "package": "cloudsmith.io/jdk:5659dd01...",
                "slug_perm": "Ft30zuSymLol",
                "status": "no_issues_found",
                "vulnerabilities": {
                    "critical": 0,
                    "high": 0,
                    "low": 0,
                    "medium": 0,
                    "unknown": 0
                }
            }
        ],
        "repository": "chainguard"
    }
}

The report includes status cards (vulnerable, no issues, not scanned), aggregate severity totals, a doughnut chart of package status, and a filterable package table.

Package status values: vulnerable, no_issues_found, no_scan.

3. Trivy format

Pass Trivy's JSON output (trivy image -f json). The tool maps ArtifactName, Results[].Vulnerabilities[], CVSS scores, and fix versions:

trivy image -f json nginx:latest > trivy-output.json
vulnly trivy-output.json

4. Grype format

Pass Grype's JSON output (grype -o json). The tool maps matches[], artifact metadata, CVSS scores, and fix versions:

grype nginx:latest -o json > grype-output.json
vulnly grype-output.json

5. Simplified format

A flat JSON structure is also supported for custom integrations:

{
    "scan_date": "2026-03-13",
    "repository": "my-org/production-repo",
    "package_name": "my-application",
    "package_version": "1.4.2",
    "package_format": "Docker",
    "scan_target": "debian 9.4",
    "package_size": "~77.4 MB",
    "scan_id": "TZR5N4HaO7nTclhz",
    "vulnerabilities": [
        {
            "severity": "critical",
            "identifier": "CVE-2026-1234",
            "package": "openssl",
            "affected_version": "1.1.1t",
            "fixed_version": "1.1.1u",
            "title": "Heap buffer overflow in OpenSSL",
            "cvss": 9.8
        }
    ]
}

Top-level fields

Field Required Description
scan_date Yes Date the scan was performed (YYYY-MM-DD)
repository Yes Namespace/repository path (e.g. my-org/production-repo)
package_name Yes Name of the scanned package
package_version Yes Version of the scanned package
package_format No Package format (e.g. Docker, Maven). Defaults to Unknown
scan_target No Scan target OS/platform (e.g. debian 9.4). Defaults to Unknown
package_size No Human-readable package size (e.g. ~77.4 MB). Defaults to Unknown
scan_id No Unique scan identifier. Defaults to N/A
vulnerabilities Yes Array of vulnerability objects

Vulnerability object fields

Field Required Description
severity Yes One of critical, high, medium, low (case-insensitive)
identifier Yes CVE ID or other identifier (e.g. GHSA-...). CVE IDs are auto-linked to NVD; GHSA IDs are linked to GitHub Advisories
package Yes Name of the affected dependency
affected_version No The vulnerable version
fixed_version No The version containing the fix, or "N/A" / omit if no fix is available
title No Short description of the vulnerability. Auto-generated if omitted
cvss No CVSS v3 score as a number (e.g. 9.8). Displayed as N/A if omitted

Requirements

  • Python 3.8+
  • No third-party packages required

You can also run without installing via:

python -m vulnly scan.json

Terminal Output

The script prints a severity breakdown after generating the report:

Report generated: reports/nginx_nginx_c755eb98e755_grype_vulnerability_report.html (162 vulnerabilities)
  HIGH: 13  MEDIUM: 29  LOW: 7

For repository summary reports:

Repo summary generated: reports/my-org_chainguard_cloudsmith_repo_summary_report.html (36 packages, 6 vulnerabilities)
  VULNERABLE: 2  NO ISSUES: 22  NOT SCANNED: 12

When no -o is specified, reports are saved to the reports/ subfolder. This directory is git-ignored by default.

License

This project is licensed under the Apache License 2.0 — see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vulnly-1.0.0b5.tar.gz (2.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vulnly-1.0.0b5-py3-none-any.whl (2.2 MB view details)

Uploaded Python 3

File details

Details for the file vulnly-1.0.0b5.tar.gz.

File metadata

  • Download URL: vulnly-1.0.0b5.tar.gz
  • Upload date:
  • Size: 2.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for vulnly-1.0.0b5.tar.gz
Algorithm Hash digest
SHA256 cfa6891dd0ccdf572c291c20a613f88efe7024ed1fc6ec806b4f44ffafc39e8c
MD5 30c8ef32879a51df4dfe9867aa624591
BLAKE2b-256 fa2053e655809d3065e2bb95bfb94fcd64a5410277def8d9362601eec268b96a

See more details on using hashes here.

File details

Details for the file vulnly-1.0.0b5-py3-none-any.whl.

File metadata

  • Download URL: vulnly-1.0.0b5-py3-none-any.whl
  • Upload date:
  • Size: 2.2 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for vulnly-1.0.0b5-py3-none-any.whl
Algorithm Hash digest
SHA256 0b9a924ddd48433a2844b835fa04f0a566e0aa4e34188aa174a43da1c098b4ee
MD5 f8aa5d2c6b2061d12fd15b7e6d91dbb1
BLAKE2b-256 cb13b2469f8ad1ebc6c7b7bea791a2b0a0b1ae542a384d005f16d32e7aa62d18

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page