What the Action does
The pompelmi GitHub Action scans your repository (or a subdirectory) for viruses and malware using ClamAV. Everything runs inside Docker on the GitHub Actions runner — no external services, no API keys, no data egress.
The Action performs these steps in order:
- Builds a Docker image based on
node:20-slimwith ClamAV installed. - Runs
freshclamto download the latest virus definitions. - Resolves the scan path (relative to the workspace root).
- Calls
scanDirectory(path)for directories, orscan(path)for single files. - Writes the
statusandinfected-filesstep outputs. - Posts a formatted table to
$GITHUB_STEP_SUMMARYso results appear in the workflow summary UI. - Exits with code 1 if any infected file is found and
fail-on-virusis'true'.
Minimal usage
Add these two steps to any workflow. The Action scans the entire workspace and fails the job if any malware is detected.
steps: - uses: actions/checkout@v4 - uses: pompelmi/pompelmi@v1.8.0
path defaults
to . (the workspace root), and fail-on-virus defaults
to 'true'.
Inputs
| Input | Default | Description |
|---|---|---|
path |
'.' |
Path to scan, relative to the workspace root. Can be a file or directory. |
fail-on-virus |
'true' |
Set to 'false' to let the job continue even when a virus is found. Use the status output to handle the result yourself. |
comment-on-pr |
'true' |
Post a comment to the pull request with scan results. Requires GITHUB_TOKEN to be available. Only runs on pull_request events. |
Outputs
| Output | Values | Description |
|---|---|---|
status |
'clean' | 'infected' |
Overall scan result. |
infected-files |
newline-separated paths, or empty string | Paths of all infected files found during the scan. Empty when status is 'clean'. |
Reference outputs in subsequent steps as
${{ steps.<id>.outputs.status }} and
${{ steps.<id>.outputs.infected-files }}.
Example: scan on every PR
This workflow scans the repository on every push to main and on
every pull request. The id field lets you reference the outputs.
name: Virus scan
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # needed for comment-on-pr
steps:
- uses: actions/checkout@v4
- name: Scan repository
id: pompelmi
uses: pompelmi/pompelmi@v1.8.0
with:
comment-on-pr: 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Print result
run: echo "Scan status: ${{ steps.pompelmi.outputs.status }}"
.github/workflows/action-example.yml.
Example: scan only uploads/
Set fail-on-virus: 'false' to inspect results yourself and take
custom action (e.g. notify a Slack channel or delete only the infected files).
steps:
- uses: actions/checkout@v4
- name: Scan uploads directory
id: scan
uses: pompelmi/pompelmi@v1.8.0
with:
path: 'uploads'
fail-on-virus: 'false'
- name: Handle infected files
if: steps.scan.outputs.status == 'infected'
run: |
echo "Infected files found:"
echo "${{ steps.scan.outputs.infected-files }}"
# add your remediation logic here
exit 1
Job summary
After each scan the Action writes a formatted table to
$GITHUB_STEP_SUMMARY. The table appears on the workflow run page
in the GitHub UI under the Summary tab.
## pompelmi scan results | File | Status | |------|--------| | src/index.js | Clean | | uploads/report.pdf | Clean | **Overall: clean** — 2 files scanned, 0 infected.
When infected files are detected, the table highlights them and the overall status row reads infected in red.
Layer caching
The Action builds a Docker image on every run. GitHub Actions caches Docker
layers automatically on ubuntu-latest runners.
| Run type | Typical duration | Notes |
|---|---|---|
| First run (cold cache) | 30–90 seconds | Builds the image and downloads ClamAV definitions from scratch. |
| Subsequent runs (warm cache) | 10–30 seconds | Docker layers are restored from cache. Only changed layers are rebuilt. |
freshclam always runs to fetch the latest definitions, even on
warm cache runs. This adds a few seconds but ensures your signatures are current.
On self-hosted runners, the Docker layer cache persists on disk between runs (no eviction), so warm runs are consistently fast. On GitHub-hosted runners, the cache is shared across the repository and may be evicted after 7 days of inactivity.
Add this badge
Show users that your repository is scanned for malware by adding the pompelmi badge to your README:
[](https://github.com/pompelmi/pompelmi)
Renders as:
BADGE.md in the repository root for additional badge variants
(SVG data URI, dark/light theme versions) with full copy-paste snippets.